/**
 * Stationery 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';

const router = express.Router();

// Escape a string for safe use inside a RegExp — a stationery name legitimately
// contains '.', '+' and other characters that would otherwise be metacharacters.
const escapeRegex = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

/** Message reused by the create route and recognised by the CSV import. */
export const STATIONERY_DUPLICATE_NAME_ERROR =
  'A stationery item with this name already exists in your company';

router.use(authenticateJwtOrApiToken);

// Get all stationery for a company
router.get('/:companyId', async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    const { Stationery } = getModels();

    if (!req.user!.companyIds.includes(companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    const items = await Stationery.find({ companyId }).sort({ createdAt: -1 });
    res.json(items);
  } catch (error) {
    res.status(500).json({ error: 'Failed to get stationery' });
  }
});

// Get single stationery
router.get('/detail/:id', async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { Stationery } = getModels();

    const item = await Stationery.findById(id);
    if (!item) {
      res.status(404).json({ error: 'Stationery not found' });
      return;
    }

    if (!req.user!.companyIds.includes(item.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    res.json(item);
  } catch (error) {
    res.status(500).json({ error: 'Failed to get stationery' });
  }
});

// Create stationery
router.post(
  '/',
  requirePermission('stationery', 'create'),
  [
    body('name').trim().notEmpty().withMessage('Stationery name is required'),
    body('companyId').notEmpty().withMessage('Company ID is required'),
    body('type').notEmpty().withMessage('Stationery type is required'),
    body('description').optional({ nullable: true }).trim().isLength({ max: 500 }).withMessage('Description cannot exceed 500 characters'),
  ],
  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 { Stationery } = getModels();

      // Reject a name that already exists in this company. Creation had no
      // duplicate check at all, so the CSV import — which POSTs one row at a
      // time — happily re-created an item that was already there (TC_603).
      // Matched case-insensitively, the same way the Employee routes do it.
      const name: string = (req.body.name || '').trim();
      if (name) {
        const duplicate = await Stationery.findOne({
          companyId: req.body.companyId,
          name: { $regex: `^${escapeRegex(name)}$`, $options: 'i' },
        });
        if (duplicate) {
          res.status(409).json({ error: STATIONERY_DUPLICATE_NAME_ERROR });
          return;
        }
      }

      const item = new Stationery(req.body);
      await item.save();

      res.status(201).json(item);
    } catch (error: any) {
      // If a unique index is added later, report the same duplicate message
      // rather than an opaque 500 (mirrors the Employee create route).
      if (error?.code === 11000) {
        res.status(409).json({ error: STATIONERY_DUPLICATE_NAME_ERROR });
        return;
      }
      res.status(500).json({ error: 'Failed to create stationery' });
    }
  }
);

// Update stationery
router.put('/:id', requirePermission('stationery', 'edit'), async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { Stationery } = getModels();

    const item = await Stationery.findById(id);
    if (!item) {
      res.status(404).json({ error: 'Stationery not found' });
      return;
    }

    if (!req.user!.companyIds.includes(item.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    Object.assign(item, req.body, { updatedAt: new Date().toISOString() });
    await item.save();

    res.json(item);
  } catch (error) {
    res.status(500).json({ error: 'Failed to update stationery' });
  }
});

// Delete stationery
router.delete('/:id', requirePermission('stationery', 'delete'), async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { Stationery } = getModels();

    const item = await Stationery.findById(id);
    if (!item) {
      res.status(404).json({ error: 'Stationery not found' });
      return;
    }

    if (!req.user!.companyIds.includes(item.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    await Stationery.findByIdAndDelete(id);
    res.json({ message: 'Stationery deleted successfully' });
  } catch (error) {
    res.status(500).json({ error: 'Failed to delete stationery' });
  }
});

export default router;
