import { Router, Request, Response, NextFunction } from 'express';
import { actionCampaignsService } from './action-campaigns.service';
import {
  createActionCampaignSchema,
  updateActionCampaignSchema,
  createActionStepSchema,
  updateActionStepSchema,
  reorderStepsSchema,
  markCompleteSchema,
} from './action-campaigns.schemas';
import { validate } from '../../middleware/validate';
import { authenticate, optionalAuth } from '../../middleware/auth.middleware';
import { requireRole } from '../../middleware/rbac.middleware';
import { INFLUENCE_ROLES } from '../../utils/roles';

const publicRouter = Router();

publicRouter.get(
  '/active',
  optionalAuth,
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (req.user?.id) {
        const data = await actionCampaignsService.getActiveForUser(req.user.id);
        res.json(data);
        return;
      }
      const campaign = await actionCampaignsService.getActiveCampaign();
      res.json(campaign);
    } catch (err) {
      next(err);
    }
  },
);

publicRouter.post(
  '/:slug/steps/:stepId/complete',
  authenticate,
  validate(markCompleteSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const stepId = req.params.stepId as string;
      const completion = await actionCampaignsService.markStepComplete(
        req.user!.id,
        stepId,
        (req.body as { source?: import('@prisma/client').ActionStepCompletionSource }).source,
      );
      res.status(201).json({ ok: true, completion });
    } catch (err) {
      next(err);
    }
  },
);

const adminRouter = Router();
adminRouter.use(authenticate);
adminRouter.use(requireRole(...INFLUENCE_ROLES));

adminRouter.get('/', async (_req: Request, res: Response, next: NextFunction) => {
  try {
    const campaigns = await actionCampaignsService.listCampaigns();
    res.json({ items: campaigns });
  } catch (err) {
    next(err);
  }
});

adminRouter.post(
  '/',
  validate(createActionCampaignSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const campaign = await actionCampaignsService.createCampaign(req.body, req.user!.id);
      res.status(201).json(campaign);
    } catch (err) {
      next(err);
    }
  },
);

adminRouter.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const campaign = await actionCampaignsService.getCampaign(id);
    res.json(campaign);
  } catch (err) {
    next(err);
  }
});

adminRouter.put(
  '/:id',
  validate(updateActionCampaignSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      const campaign = await actionCampaignsService.updateCampaign(id, req.body);
      res.json(campaign);
    } catch (err) {
      next(err);
    }
  },
);

adminRouter.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    await actionCampaignsService.deleteCampaign(id);
    res.status(204).send();
  } catch (err) {
    next(err);
  }
});

adminRouter.post('/:id/activate', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const campaign = await actionCampaignsService.activateCampaign(id);
    res.json(campaign);
  } catch (err) {
    next(err);
  }
});

adminRouter.post(
  '/:id/steps',
  validate(createActionStepSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      const step = await actionCampaignsService.addStep(id, req.body);
      res.status(201).json(step);
    } catch (err) {
      next(err);
    }
  },
);

adminRouter.put(
  '/:id/steps/:stepId',
  validate(updateActionStepSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const stepId = req.params.stepId as string;
      const step = await actionCampaignsService.updateStep(stepId, req.body);
      res.json(step);
    } catch (err) {
      next(err);
    }
  },
);

adminRouter.delete('/:id/steps/:stepId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const stepId = req.params.stepId as string;
    await actionCampaignsService.deleteStep(stepId);
    res.status(204).send();
  } catch (err) {
    next(err);
  }
});

adminRouter.post(
  '/:id/steps/reorder',
  validate(reorderStepsSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      const { stepIds } = req.body as { stepIds: string[] };
      const steps = await actionCampaignsService.reorderSteps(id, stepIds);
      res.json(steps);
    } catch (err) {
      next(err);
    }
  },
);

export { publicRouter as actionCampaignsRouter, adminRouter as actionCampaignsAdminRouter };
