import { Router, Request, Response, NextFunction } from 'express';
import { meetingPlannerService } from './meeting-planner.service';
import {
  createPollSchema,
  updatePollSchema,
  addOptionsSchema,
  updateOptionSchema,
  submitVotesSchema,
  submitCommentSchema,
  finalizePollSchema,
  convertToShiftSchema,
  listPollsSchema,
} from './meeting-planner.schemas';
import { validate } from '../../middleware/validate';
import { authenticate, optionalAuth } from '../../middleware/auth.middleware';
import { requireRole } from '../../middleware/rbac.middleware';
import { pollVoteRateLimit, pollCommentRateLimit } from './meeting-planner.rate-limits';
import { EVENTS_ROLES } from '../../utils/roles';

// --- Admin Router ---

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

// List polls
adminRouter.get('/', validate(listPollsSchema, 'query'), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const result = await meetingPlannerService.findAll(req.query as any);
    res.json(result);
  } catch (err) { next(err); }
});

// Get poll detail
adminRouter.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const poll = await meetingPlannerService.findById(id);
    res.json(poll);
  } catch (err) { next(err); }
});

// Create poll
adminRouter.post('/', validate(createPollSchema), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const poll = await meetingPlannerService.create(req.body, req.user!.id);
    res.status(201).json(poll);
  } catch (err) { next(err); }
});

// Update poll
adminRouter.put('/:id', validate(updatePollSchema), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const poll = await meetingPlannerService.update(id, req.body);
    res.json(poll);
  } catch (err) { next(err); }
});

// Delete poll
adminRouter.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    await meetingPlannerService.delete(id);
    res.json({ message: 'Poll deleted' });
  } catch (err) { next(err); }
});

// Add options
adminRouter.post('/:id/options', validate(addOptionsSchema), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const poll = await meetingPlannerService.addOptions(id, req.body);
    res.json(poll);
  } catch (err) { next(err); }
});

// Update option
adminRouter.put('/:id/options/:optionId', validate(updateOptionSchema), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const optionId = req.params.optionId as string;
    const poll = await meetingPlannerService.updateOption(id, optionId, req.body);
    res.json(poll);
  } catch (err) { next(err); }
});

// Remove option
adminRouter.delete('/:id/options/:optionId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const optionId = req.params.optionId as string;
    const poll = await meetingPlannerService.removeOption(id, optionId);
    res.json(poll);
  } catch (err) { next(err); }
});

// Finalize poll
adminRouter.post('/:id/finalize', validate(finalizePollSchema), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const poll = await meetingPlannerService.finalize(id, req.body);
    res.json(poll);
  } catch (err) { next(err); }
});

// Convert to shift
adminRouter.post('/:id/convert-to-shift', validate(convertToShiftSchema), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const shift = await meetingPlannerService.convertToShift(id, req.body);
    res.json(shift);
  } catch (err) { next(err); }
});

// Convert to Gancio event
adminRouter.post('/:id/convert-to-event', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const result = await meetingPlannerService.convertToEvent(id);
    res.json(result);
  } catch (err) { next(err); }
});

// Remove voter
adminRouter.delete('/:id/voters/:voterKey', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const voterKey = decodeURIComponent(req.params.voterKey as string);
    const poll = await meetingPlannerService.removeVoter(id, voterKey);
    res.json(poll);
  } catch (err) { next(err); }
});

// Delete comment
adminRouter.delete('/:id/comments/:commentId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = req.params.id as string;
    const commentId = req.params.commentId as string;
    await meetingPlannerService.deleteComment(id, commentId);
    res.json({ message: 'Comment deleted' });
  } catch (err) { next(err); }
});

// --- Public Router ---

const publicRouter = Router();

// Public listing of open polls
publicRouter.get('/public', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const result = await meetingPlannerService.findAllPublic({
      status: 'OPEN',
      limit: 50,
      page: 1,
    });
    res.json(result);
  } catch (err) { next(err); }
});

// View poll by slug
publicRouter.get('/public/:slug', optionalAuth, async (req: Request, res: Response, next: NextFunction) => {
  try {
    const slug = req.params.slug as string;
    const poll = await meetingPlannerService.findBySlugPublic(slug, req.user?.id);
    res.json(poll);
  } catch (err) { next(err); }
});

// Submit votes
publicRouter.post('/public/:slug/vote', optionalAuth, pollVoteRateLimit, validate(submitVotesSchema), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const slug = req.params.slug as string;
    const result = await meetingPlannerService.submitVotes(slug, req.body, req.user?.id);
    res.json(result);
  } catch (err) { next(err); }
});

// Add comment
publicRouter.post('/public/:slug/comment', optionalAuth, pollCommentRateLimit, validate(submitCommentSchema), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const slug = req.params.slug as string;
    const comment = await meetingPlannerService.addComment(slug, req.body, req.user?.id);
    res.status(201).json(comment);
  } catch (err) { next(err); }
});

export { adminRouter as meetingPlannerAdminRouter, publicRouter as meetingPlannerPublicRouter };
