/**
 * Cap Table Routes
 *
 * Shareholder tracking, ownership percentages, dilution analysis, and vesting schedules.
 */

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);

// Get cap table for a company (singleton - one per company)
router.get('/:companyId', async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    const { CapTable } = getModels();

    if (!req.user!.companyIds.includes(companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    let capTable = await CapTable.findOne({ companyId });

    // Create default cap table if none exists
    if (!capTable) {
      capTable = new CapTable({
        companyId,
        shareholders: [],
        totalShares: 0,
        totalFullyDiluted: 0,
        createdBy: req.user!._id,
      });
      await capTable.save();
    }

    res.json(capTable);
  } catch (error) {
    res.status(500).json({ error: 'Failed to get cap table' });
  }
});

// Create/Update cap table (upsert)
router.put(
  '/:companyId',
  requirePermission('funding', 'edit'),
  async (req: Request, res: Response) => {
    try {
      const { companyId } = req.params;
      const { CapTable } = getModels();

      if (!req.user!.companyIds.includes(companyId) && req.user!.role !== 'admin') {
        res.status(403).json({ error: 'Access denied' });
        return;
      }

      const cleanBody = Object.fromEntries(
        Object.entries(req.body).filter(([, v]) => v !== '')
      );

      let capTable = await CapTable.findOne({ companyId });

      if (capTable) {
        // Update existing
        Object.assign(capTable, cleanBody, {
          updatedAt: new Date(),
          lastUpdated: new Date(),
        });
        await capTable.save();
      } else {
        // Create new
        capTable = new CapTable({
          ...cleanBody,
          companyId,
          createdBy: req.user!._id,
        });
        await capTable.save();
      }

      res.json(capTable);
    } catch (error: any) {
      console.error('[CapTable Update Error]', error?.message || error);
      res.status(500).json({ error: 'Failed to update cap table', details: error?.message });
    }
  }
);

// Add shareholder
router.post(
  '/:companyId/shareholders',
  requirePermission('funding', 'create'),
  [
    body('name').trim().notEmpty().withMessage('Shareholder name is required'),
    body('type').isIn(['founder', 'employee', 'investor', 'option-pool', 'convertible', 'other']).withMessage('Invalid shareholder type'),
    body('shares').isNumeric().withMessage('Shares is required'),
  ],
  async (req: Request, res: Response) => {
    try {
      const errors = validationResult(req);
      if (!errors.isEmpty()) {
        res.status(400).json({ errors: errors.array() });
        return;
      }

      const { companyId } = req.params;
      const { CapTable } = getModels();

      if (!req.user!.companyIds.includes(companyId) && req.user!.role !== 'admin') {
        res.status(403).json({ error: 'Access denied' });
        return;
      }

      let capTable = await CapTable.findOne({ companyId });
      if (!capTable) {
        capTable = new CapTable({
          companyId,
          shareholders: [],
          totalShares: 0,
          totalFullyDiluted: 0,
          createdBy: req.user!._id,
        });
      }

      capTable.shareholders.push({
        ...req.body,
        id: `shareholder-${Date.now()}`,
      });
      capTable.updatedAt = new Date();
      capTable.lastUpdated = new Date();
      await capTable.save();

      res.json(capTable);
    } catch (error: any) {
      console.error('[CapTable Add Shareholder Error]', error?.message || error);
      res.status(500).json({ error: 'Failed to add shareholder', details: error?.message });
    }
  }
);

// Update shareholder
router.put('/:companyId/shareholders/:shareholderId', requirePermission('funding', 'edit'), async (req: Request, res: Response) => {
  try {
    const { companyId, shareholderId } = req.params;
    const { CapTable } = getModels();

    let capTable = await CapTable.findOne({ companyId });
    if (!capTable) {
      res.status(404).json({ error: 'Cap table not found' });
      return;
    }

    if (!req.user!.companyIds.includes(capTable.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    const shareholderIndex = capTable.shareholders.findIndex((s: any) => s.id === shareholderId);
    if (shareholderIndex === -1) {
      res.status(404).json({ error: 'Shareholder not found' });
      return;
    }

    capTable.shareholders[shareholderIndex] = {
      ...capTable.shareholders[shareholderIndex].toObject(),
      ...req.body,
    };
    capTable.updatedAt = new Date();
    capTable.lastUpdated = new Date();
    await capTable.save();

    res.json(capTable);
  } catch (error) {
    res.status(500).json({ error: 'Failed to update shareholder' });
  }
});

// Delete shareholder
router.delete('/:companyId/shareholders/:shareholderId', requirePermission('funding', 'delete'), async (req: Request, res: Response) => {
  try {
    const { companyId, shareholderId } = req.params;
    const { CapTable } = getModels();

    let capTable = await CapTable.findOne({ companyId });
    if (!capTable) {
      res.status(404).json({ error: 'Cap table not found' });
      return;
    }

    if (!req.user!.companyIds.includes(capTable.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    capTable.shareholders = capTable.shareholders.filter((s: any) => s.id !== shareholderId);
    capTable.updatedAt = new Date();
    capTable.lastUpdated = new Date();
    await capTable.save();

    res.json(capTable);
  } catch (error) {
    res.status(500).json({ error: 'Failed to delete shareholder' });
  }
});

// Add dilution scenario
router.post('/:companyId/dilution-scenario', requirePermission('funding', 'create'), async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    const { CapTable } = getModels();

    let capTable = await CapTable.findOne({ companyId });
    if (!capTable) {
      capTable = new CapTable({
        companyId,
        shareholders: [],
        totalShares: 0,
        totalFullyDiluted: 0,
        createdBy: req.user!._id,
      });
    }

    if (!capTable.dilutionScenarios) {
      capTable.dilutionScenarios = [];
    }

    capTable.dilutionScenarios.push({
      ...req.body,
      id: `scenario-${Date.now()}`,
      createdAt: new Date(),
    });
    capTable.updatedAt = new Date();
    capTable.lastUpdated = new Date();
    await capTable.save();

    res.json(capTable);
  } catch (error) {
    res.status(500).json({ error: 'Failed to add dilution scenario' });
  }
});

// Delete dilution scenario
router.delete('/:companyId/dilution-scenario/:scenarioId', requirePermission('funding', 'delete'), async (req: Request, res: Response) => {
  try {
    const { companyId, scenarioId } = req.params;
    const { CapTable } = getModels();

    let capTable = await CapTable.findOne({ companyId });
    if (!capTable) {
      res.status(404).json({ error: 'Cap table not found' });
      return;
    }

    if (!req.user!.companyIds.includes(capTable.companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    if (capTable.dilutionScenarios) {
      capTable.dilutionScenarios = capTable.dilutionScenarios.filter((s: any) => s.id !== scenarioId);
    }
    capTable.updatedAt = new Date();
    capTable.lastUpdated = new Date();
    await capTable.save();

    res.json(capTable);
  } catch (error) {
    res.status(500).json({ error: 'Failed to delete dilution scenario' });
  }
});

// Get ownership pie chart data
router.get('/:companyId/ownership-pie', async (req: Request, res: Response) => {
  try {
    const { companyId } = req.params;
    const { CapTable } = getModels();

    if (!req.user!.companyIds.includes(companyId) && req.user!.role !== 'admin') {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    const capTable = await CapTable.findOne({ companyId });
    if (!capTable) {
      res.json({ shareholders: [], totalShares: 0 });
      return;
    }

    // Group by shareholder type
    const byType: Record<string, { name: string; shares: number; percentage: number }> = {};
    capTable.shareholders.forEach((s: any) => {
      if (!byType[s.type]) {
        byType[s.type] = { name: s.type, shares: 0, percentage: 0 };
      }
      byType[s.type].shares += s.shares;
    });

    // Calculate percentages
    const totalShares = Object.values(byType).reduce((sum, t) => sum + t.shares, 0);
    Object.values(byType).forEach(t => {
      t.percentage = totalShares > 0 ? Math.round((t.shares / totalShares) * 10000) / 100 : 0;
    });

    res.json({
      shareholders: capTable.shareholders,
      byType: Object.values(byType),
      totalShares,
      totalFullyDiluted: capTable.totalFullyDiluted,
    });
  } catch (error) {
    res.status(500).json({ error: 'Failed to get ownership data' });
  }
});

export default router;