/**
 * Marketing Channels Map Routes
 *
 * CRUD for MarketingChannel and ChannelMap
 */

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('[MarketingChannels] Error:', error.message);
  res.status(500).json({ error: error.message });
};

// ============================================
// MARKETING CHANNELS
// ============================================

// LIST channels by company
router.get('/channels/:companyId', async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    if (!authorizeCompany(req, companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    const { MarketingChannel } = getModels();
    const channels = await MarketingChannel.find({ companyId }).sort({ channelType: 1, name: 1 });
    res.json(channels);
  } catch (error: any) {
    handleError(res, error);
  }
});

// GET single channel
router.get('/channels/detail/:id', async (req: Request, res: Response) => {
  try {
    const { MarketingChannel } = getModels();
    const channel = await MarketingChannel.findById(req.params.id);
    if (!channel) {
      res.status(404).json({ error: 'Channel not found' });
      return;
    }
    if (!authorizeCompany(req, (channel as any).companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    res.json(channel);
  } catch (error: any) {
    handleError(res, error);
  }
});

// CREATE channel
router.post('/channels', requirePermission('marketing-channels', 'create'), [
  body('companyId').notEmpty().withMessage('Company ID is required'),
  // Length ceilings mirror the frontend CHANNEL_LIMITS (Create/Edit Channel modals)
  // and the Mongoose schema 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('channelType').notEmpty().withMessage('Channel type is required'),
  body('platform').optional().isLength({ max: 100 }).withMessage('Platform must be 100 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/ROI are non-negative — mirrors the frontend clamp and the schema min:0.
  body('budgetAllocated').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('Budget Allocated cannot be negative'),
  body('budgetSpent').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('Budget Spent cannot be negative'),
  body('roi').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('ROI 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 { MarketingChannel } = getModels();
    const channel = await MarketingChannel.create(req.body);
    res.status(201).json(channel);
  } catch (error: any) {
    handleError(res, error);
  }
});

// UPDATE channel
router.put('/channels/:id', requirePermission('marketing-channels', 'edit'), [
  // Same length ceilings 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('platform').optional().isLength({ max: 100 }).withMessage('Platform must be 100 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('budgetSpent').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('Budget Spent cannot be negative'),
  body('roi').optional({ nullable: true }).isFloat({ min: 0 }).withMessage('ROI 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 { MarketingChannel } = getModels();
    const channel = await MarketingChannel.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
    if (!channel) {
      res.status(404).json({ error: 'Channel not found' });
      return;
    }
    res.json(channel);
  } catch (error: any) {
    handleError(res, error);
  }
});

// DELETE channel
router.delete('/channels/:id', requirePermission('marketing-channels', 'delete'), async (req: Request, res: Response) => {
  try {
    const { MarketingChannel } = getModels();
    const channel = await MarketingChannel.findByIdAndDelete(req.params.id);
    if (!channel) {
      res.status(404).json({ error: 'Channel not found' });
      return;
    }
    res.json({ message: 'Channel deleted' });
  } catch (error: any) {
    handleError(res, error);
  }
});

// ============================================
// CHANNEL MAPS
// ============================================

// LIST maps by company
router.get('/maps/:companyId', async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    if (!authorizeCompany(req, companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    const { ChannelMap } = getModels();
    const maps = await ChannelMap.find({ companyId }).sort({ createdAt: -1 });
    res.json(maps);
  } catch (error: any) {
    handleError(res, error);
  }
});

// GET single map
router.get('/maps/detail/:id', async (req: Request, res: Response) => {
  try {
    const { ChannelMap } = getModels();
    const map = await ChannelMap.findById(req.params.id);
    if (!map) {
      res.status(404).json({ error: 'Channel map not found' });
      return;
    }
    if (!authorizeCompany(req, (map as any).companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }
    res.json(map);
  } catch (error: any) {
    handleError(res, error);
  }
});

// CREATE map
router.post('/maps', requirePermission('marketing-channels', 'create'), [
  body('companyId').notEmpty().withMessage('Company ID is required'),
  body('name').notEmpty().withMessage('Name is required'),
], 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 { ChannelMap } = getModels();
    const map = await ChannelMap.create(req.body);
    res.status(201).json(map);
  } catch (error: any) {
    handleError(res, error);
  }
});

// UPDATE map
router.put('/maps/:id', requirePermission('marketing-channels', 'edit'), async (req: Request, res: Response) => {
  try {
    const { ChannelMap } = getModels();
    const map = await ChannelMap.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
    if (!map) {
      res.status(404).json({ error: 'Channel map not found' });
      return;
    }
    res.json(map);
  } catch (error: any) {
    handleError(res, error);
  }
});

// DELETE map
router.delete('/maps/:id', requirePermission('marketing-channels', 'delete'), async (req: Request, res: Response) => {
  try {
    const { ChannelMap } = getModels();
    const map = await ChannelMap.findByIdAndDelete(req.params.id);
    if (!map) {
      res.status(404).json({ error: 'Channel map not found' });
      return;
    }
    res.json({ message: 'Channel map deleted' });
  } catch (error: any) {
    handleError(res, error);
  }
});

export default router;