/**
 * CashFlowController - Controlador de Flujo de Efectivo
 *
 * Endpoints para proyecciones y análisis de flujo de efectivo.
 *
 * @module Finance
 */

import { Router, Request, Response } from 'express';
import { DataSource } from 'typeorm';
import { CashFlowService } from '../services';

export function createCashFlowController(dataSource: DataSource): Router {
  const router = Router();
  const service = new CashFlowService(dataSource);

  // ==================== PROYECCIONES ====================

  /**
   * GET /
   * Lista proyecciones con filtros
   */
  router.get('/', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const options = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 20,
        flowType: req.query.flowType as any,
        periodType: req.query.periodType as any,
        projectId: req.query.projectId as string,
        fiscalYear: req.query.fiscalYear ? parseInt(req.query.fiscalYear as string) : undefined,
        startDate: req.query.startDate ? new Date(req.query.startDate as string) : undefined,
        endDate: req.query.endDate ? new Date(req.query.endDate as string) : undefined,
      };

      const result = await service.findAll(ctx, options);
      res.json(result);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /dashboard
   * Obtiene datos del dashboard
   */
  router.get('/dashboard', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const data = await service.getDashboardData(ctx);
      res.json(data);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /summary
   * Obtiene resumen de flujo de efectivo
   */
  router.get('/summary', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const startDate = new Date(req.query.startDate as string);
      const endDate = new Date(req.query.endDate as string);

      if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
        res.status(400).json({ error: 'Fechas inválidas' });
        return;
      }

      const options = {
        periodType: req.query.periodType as any,
        flowType: req.query.flowType as any,
        projectId: req.query.projectId as string,
      };

      const summary = await service.getCashFlowSummary(ctx, startDate, endDate, options);
      res.json(summary);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /variance
   * Obtiene análisis de varianza
   */
  router.get('/variance', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const fiscalYear = parseInt(req.query.fiscalYear as string) || new Date().getFullYear();
      const options = {
        projectId: req.query.projectId as string,
      };

      const analysis = await service.getVarianceAnalysis(ctx, fiscalYear, options);
      res.json(analysis);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /:id
   * Obtiene una proyección por ID
   */
  router.get('/:id', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const projection = await service.findById(ctx, req.params.id);
      if (!projection) {
        res.status(404).json({ error: 'Proyección no encontrada' });
        return;
      }

      res.json(projection);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /
   * Crea una nueva proyección
   */
  router.post('/', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const projection = await service.create(ctx, req.body);
      res.status(201).json(projection);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * PUT /:id
   * Actualiza una proyección
   */
  router.put('/:id', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const projection = await service.update(ctx, req.params.id, req.body);
      res.json(projection);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /:id/lock
   * Bloquea una proyección
   */
  router.post('/:id/lock', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const projection = await service.lock(ctx, req.params.id);
      res.json(projection);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * DELETE /:id
   * Elimina una proyección
   */
  router.delete('/:id', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      await service.delete(ctx, req.params.id);
      res.status(204).send();
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  // ==================== GENERACIÓN AUTOMÁTICA ====================

  /**
   * POST /generate
   * Genera proyección automática para un periodo
   */
  router.post('/generate', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const { periodStart, periodEnd, periodType, projectId, projectCode } = req.body;

      if (!periodStart || !periodEnd) {
        res.status(400).json({ error: 'Se requieren fechas de inicio y fin' });
        return;
      }

      const projection = await service.generateProjection(
        ctx,
        new Date(periodStart),
        new Date(periodEnd),
        { periodType, projectId, projectCode }
      );

      res.status(201).json(projection);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /generate-multiple
   * Genera múltiples proyecciones (ej: 4 semanas)
   */
  router.post('/generate-multiple', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const { startDate, weeks, projectId, projectCode } = req.body;

      if (!startDate || !weeks) {
        res.status(400).json({ error: 'Se requiere fecha de inicio y número de semanas' });
        return;
      }

      const projections = await service.generateMultiplePeriods(
        ctx,
        new Date(startDate),
        parseInt(weeks),
        { projectId, projectCode }
      );

      res.status(201).json(projections);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /:id/compare
   * Crea comparación proyectado vs real
   */
  router.post('/:id/compare', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const comparison = await service.createComparison(ctx, req.params.id);
      res.status(201).json(comparison);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  return router;
}
