/**
 * ICP (Ideal Customer Profile) Routes
 */

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';
import {
  EMPLOYEE_COUNT_MAX,
  EMPLOYEE_COUNT_MIN,
  normaliseEmployeeCount,
} from '../utils/numericValidation';

const router = express.Router();

/**
 * Employee Count guard, shared by create + update.
 *
 * Normalises first (so a generated or imported "1,500 employees" / "50-200" still
 * saves as a clean number) and rejects only what cannot represent a positive whole
 * count — negatives, zero, letters, symbols. Mirrors the frontend's
 * `validateEmployeeCount`.
 */
const employeeCountValidator = body('employeeCount')
  .optional({ checkFalsy: true })
  .customSanitizer((value) => normaliseEmployeeCount(value) ?? value)
  .custom((value) => normaliseEmployeeCount(value) !== null)
  .withMessage(
    `Employee count must be a whole number between ${EMPLOYEE_COUNT_MIN} and ${EMPLOYEE_COUNT_MAX}`,
  );

router.use(authenticateJwtOrApiToken);

// Get all ICPs for a company
router.get('/:companyId', async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    const { ICP } = getModels();

    if (!req.user!.companyIds.includes(companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    const icps = await ICP.find({ companyId });
    res.json(icps);
  } catch (error) {
    res.status(500).json({ error: 'Failed to get ICPs' });
  }
});

// Get single ICP
router.get('/detail/:id', async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { ICP } = getModels();

    const icp = await ICP.findById(id);
    if (!icp) {
      res.status(404).json({ error: 'ICP not found' });
      return;
    }

    if (!req.user!.companyIds.includes(icp.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    res.json(icp);
  } catch (error) {
    res.status(500).json({ error: 'Failed to get ICP' });
  }
});

// Create ICP
router.post(
  '/',
  requirePermission('icp-personas', 'create'),
  [
    body('name').trim().notEmpty().withMessage('ICP name is required'),
    body('companyId').notEmpty().withMessage('Company ID is required'),
    body('isActive').optional().isBoolean(),
    employeeCountValidator,
  ],
  async (req: Request, res: Response) => {
    try {
      const errors = validationResult(req);
      if (!errors.isEmpty()) {
        res.status(400).json({ errors: errors.array() });
        return;
      }

      if (!req.user!.companyIds.includes(req.body.companyId) && req.user!.role !== 'admin') {
        res.status(403).json({ error: 'Access denied' });
        return;
      }

      const { ICP } = getModels();
      const icp = new ICP({
        ...req.body,
        isActive: req.body.isActive ?? true,
      });
      await icp.save();

      res.status(201).json(icp);
    } catch (error) {
      res.status(500).json({ error: 'Failed to create ICP' });
    }
  }
);

// Update ICP
router.put(
  '/:id',
  requirePermission('icp-personas', 'edit'),
  [employeeCountValidator],
  async (req: Request, res: Response) => {
  try {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ errors: errors.array() });
      return;
    }

    const { id } = req.params;
    const { ICP } = getModels();

    const icp = await ICP.findById(id);
    if (!icp) {
      res.status(404).json({ error: 'ICP not found' });
      return;
    }

    if (!req.user!.companyIds.includes(icp.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    Object.assign(icp, req.body, { updatedAt: new Date().toISOString() });
    await icp.save();

    res.json(icp);
  } catch (error) {
    res.status(500).json({ error: 'Failed to update ICP' });
  }
});

// Delete ICP
router.delete('/:id', requirePermission('icp-personas', 'delete'), async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { ICP, Product, Persona } = getModels();

    const icp = await ICP.findById(id);
    if (!icp) {
      res.status(404).json({ error: 'ICP not found' });
      return;
    }

    if (!req.user!.companyIds.includes(icp.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    // Cascade: Remove this ICP's ID from all Products that reference it
    await Product.updateMany({ icpIds: id }, { $pull: { icpIds: id } });

    // Cascade: Find child Personas before deleting them
    const childPersonas = await Persona.find({ icpId: id });
    const childPersonaIds = childPersonas.map((p: any) => p._id.toString());

    // Cascade: Delete child Personas and clean up their references
    if (childPersonaIds.length > 0) {
      await Persona.deleteMany({ icpId: id });
      // Remove deleted Persona IDs from all Products that reference them
      await Product.updateMany(
        { personaIds: { $in: childPersonaIds } },
        { $pull: { personaIds: { $in: childPersonaIds } } },
      );
    }

    await ICP.findByIdAndDelete(id);
    res.json({ message: 'ICP deleted successfully' });
  } catch (error) {
    res.status(500).json({ error: 'Failed to delete ICP' });
  }
});

export default router;
