/**
 * Marketing Calendar & Timing Routes
 *
 * CRUD for MarketingCalendarEvent and SeasonalPlan
 */

import express, { Request, Response } from 'express';
import { body, validationResult } from 'express-validator';
import { getModels } from '../models';
import { authenticateJwtOrApiToken } from '../middleware/dualAuth';
import { requirePermission } from '../middleware/permissions';

const router = express.Router();
router.use(authenticateJwtOrApiToken);

// Helper: authorize company access
const authorizeCompany = (req: Request, companyId: string): boolean => {
  return req.user!.companyIds.includes(companyId) || req.user!.role === 'admin';
};

const handleError = (res: Response, error: any) => {
  if (error.name === 'ValidationError') {
    res.status(400).json({ error: error.message, details: Object.values(error.errors).map((e: any) => e.message) });
    return;
  }
  console.error('[MarketingCalendar] Error:', error.message);
  res.status(500).json({ error: error.message });
};

// ============================================
// MARKETING CALENDAR EVENTS
// ============================================

// LIST events by company
router.get('/events/:companyId', async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    if (!authorizeCompany(req, companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    const { MarketingCalendarEvent } = getModels();
    const events = await MarketingCalendarEvent.find({ companyId }).sort({ startDate: 1 });
    res.json(events);
  } catch (error: any) {
    handleError(res, error);
  }
});

// GET single event
router.get('/events/detail/:id', async (req: Request, res: Response) => {
  try {
    const { MarketingCalendarEvent } = getModels();
    const event = await MarketingCalendarEvent.findById(req.params.id);
    if (!event) {
      res.status(404).json({ error: 'Event not found' });
      return;
    }
    if (!authorizeCompany(req, (event as any).companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    res.json(event);
  } catch (error: any) {
    handleError(res, error);
  }
});

// CREATE event
router.post('/events', requirePermission('marketing-calendar', 'create'), [
  body('companyId').notEmpty().withMessage('Company ID is required'),
  body('title').notEmpty().withMessage('Title is required')
    .isLength({ max: 200 }).withMessage('Title must be 200 characters or fewer'),
  body('startDate').notEmpty().withMessage('Start date is required'),
  // Character limits mirror the frontend CAL_EVENT_LIMITS (Create/Edit Event modals)
  // so a direct API request cannot store oversized text.
  body('targetAudience').optional().isLength({ max: 200 }).withMessage('Target audience must be 200 characters or fewer'),
  body('description').optional().isLength({ max: 1000 }).withMessage('Description must be 1000 characters or fewer'),
  body('notes').optional().isLength({ max: 1000 }).withMessage('Notes must be 1000 characters or fewer'),
  // Budget amounts are non-negative — mirrors the frontend min={0} clamp and blocks
  // negative values reaching the DB via a direct API request.
  body('budgetAllocated').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('Budget Allocated cannot be negative'),
  body('budgetActual').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('Actual Spend cannot be negative'),
], async (req: Request, res: Response) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    res.status(400).json({ errors: errors.array() });
    return;
  }
  try {
    const { companyId } = req.body;
    if (!authorizeCompany(req, companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    const { MarketingCalendarEvent } = getModels();
    const event = await MarketingCalendarEvent.create(req.body);
    res.status(201).json(event);
  } catch (error: any) {
    handleError(res, error);
  }
});

// UPDATE event
router.put('/events/:id', requirePermission('marketing-calendar', 'edit'), [
  // Same length + non-negative budget rules as create — blocks a direct API bypass on update.
  body('title').optional().isLength({ max: 200 }).withMessage('Title must be 200 characters or fewer'),
  body('targetAudience').optional().isLength({ max: 200 }).withMessage('Target audience must be 200 characters or fewer'),
  body('description').optional().isLength({ max: 1000 }).withMessage('Description must be 1000 characters or fewer'),
  body('notes').optional().isLength({ max: 1000 }).withMessage('Notes must be 1000 characters or fewer'),
  body('budgetAllocated').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('Budget Allocated cannot be negative'),
  body('budgetActual').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('Actual Spend cannot be negative'),
], async (req: Request, res: Response) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    res.status(400).json({ errors: errors.array() });
    return;
  }
  try {
    const { MarketingCalendarEvent } = getModels();
    const event = await MarketingCalendarEvent.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
    if (!event) {
      res.status(404).json({ error: 'Event not found' });
      return;
    }
    res.json(event);
  } catch (error: any) {
    handleError(res, error);
  }
});

// DELETE event
router.delete('/events/:id', requirePermission('marketing-calendar', 'delete'), async (req: Request, res: Response) => {
  try {
    const { MarketingCalendarEvent } = getModels();
    const event = await MarketingCalendarEvent.findByIdAndDelete(req.params.id);
    if (!event) {
      res.status(404).json({ error: 'Event not found' });
      return;
    }
    res.json({ message: 'Calendar event deleted' });
  } catch (error: any) {
    handleError(res, error);
  }
});

// ============================================
// SEASONAL PLANS
// ============================================

// LIST seasonal plans by company
router.get('/seasonal-plans/:companyId', async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    if (!authorizeCompany(req, companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    const { SeasonalPlan } = getModels();
    const plans = await SeasonalPlan.find({ companyId }).sort({ year: -1, season: 1 });
    res.json(plans);
  } catch (error: any) {
    handleError(res, error);
  }
});

// GET single seasonal plan
router.get('/seasonal-plans/detail/:id', async (req: Request, res: Response) => {
  try {
    const { SeasonalPlan } = getModels();
    const plan = await SeasonalPlan.findById(req.params.id);
    if (!plan) {
      res.status(404).json({ error: 'Seasonal plan not found' });
      return;
    }
    if (!authorizeCompany(req, (plan as any).companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    res.json(plan);
  } catch (error: any) {
    handleError(res, error);
  }
});

// CREATE seasonal plan
router.post('/seasonal-plans', requirePermission('marketing-calendar', 'create'), [
  body('companyId').notEmpty().withMessage('Company ID is required'),
  // Name/Description length mirror the frontend SEASONAL_PLAN_LIMITS so a direct
  // API request cannot store oversized text.
  body('name').notEmpty().withMessage('Name is required')
    .isLength({ max: 200 }).withMessage('Name must be 200 characters or fewer'),
  body('description').optional().isLength({ max: 1000 }).withMessage('Description must be 1000 characters or fewer'),
  body('season').notEmpty().withMessage('Season is required'),
  // Year must be a valid 4-digit year (2000–2100) — rejects negatives, 2-digit,
  // 5-digit and non-numeric values, mirroring the frontend validateYear rule.
  body('year').isInt({ min: 2000, max: 2100 }).withMessage('Year must be a valid 4-digit year (2000–2100)'),
], async (req: Request, res: Response) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    res.status(400).json({ errors: errors.array() });
    return;
  }
  try {
    const { companyId } = req.body;
    if (!authorizeCompany(req, companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    const { SeasonalPlan } = getModels();
    const plan = await SeasonalPlan.create(req.body);
    res.status(201).json(plan);
  } catch (error: any) {
    handleError(res, error);
  }
});

// UPDATE seasonal plan
router.put('/seasonal-plans/:id', requirePermission('marketing-calendar', 'edit'), [
  // Same length + valid-year rules as create — blocks a direct API bypass on update.
  body('name').optional().notEmpty().withMessage('Name is required')
    .isLength({ max: 200 }).withMessage('Name must be 200 characters or fewer'),
  body('description').optional().isLength({ max: 1000 }).withMessage('Description must be 1000 characters or fewer'),
  body('year').optional().isInt({ min: 2000, max: 2100 }).withMessage('Year must be a valid 4-digit year (2000–2100)'),
], async (req: Request, res: Response) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    res.status(400).json({ errors: errors.array() });
    return;
  }
  try {
    const { SeasonalPlan } = getModels();
    const plan = await SeasonalPlan.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
    if (!plan) {
      res.status(404).json({ error: 'Seasonal plan not found' });
      return;
    }
    res.json(plan);
  } catch (error: any) {
    handleError(res, error);
  }
});

// DELETE seasonal plan
router.delete('/seasonal-plans/:id', requirePermission('marketing-calendar', 'delete'), async (req: Request, res: Response) => {
  try {
    const { SeasonalPlan } = getModels();
    const plan = await SeasonalPlan.findByIdAndDelete(req.params.id);
    if (!plan) {
      res.status(404).json({ error: 'Seasonal plan not found' });
      return;
    }
    res.json({ message: 'Seasonal plan deleted' });
  } catch (error: any) {
    handleError(res, error);
  }
});

export default router;