/**
 * ReportsController - Controlador de Reportes Financieros
 *
 * Endpoints para estados financieros y exportación.
 *
 * @module Finance
 */

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

export function createReportsController(dataSource: DataSource): Router {
  const router = Router();
  const reportsService = new FinancialReportsService(dataSource);
  const integrationService = new ERPIntegrationService(dataSource);

  // ==================== ESTADOS FINANCIEROS ====================

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

      const asOfDate = req.query.asOfDate
        ? new Date(req.query.asOfDate as string)
        : new Date();

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

      const report = await reportsService.generateBalanceSheet(ctx, asOfDate, options);
      res.json(report);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /income-statement
   * Genera estado de resultados
   */
  router.get('/income-statement', 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 = new Date(req.query.periodStart as string);
      const periodEnd = new Date(req.query.periodEnd as string);

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

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

      const report = await reportsService.generateIncomeStatement(
        ctx,
        periodStart,
        periodEnd,
        options
      );
      res.json(report);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /cash-flow-statement
   * Genera estado de flujo de efectivo
   */
  router.get('/cash-flow-statement', 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 = new Date(req.query.periodStart as string);
      const periodEnd = new Date(req.query.periodEnd as string);

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

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

      const report = await reportsService.generateCashFlowStatement(
        ctx,
        periodStart,
        periodEnd,
        options
      );
      res.json(report);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /trial-balance
   * Genera balanza de comprobación
   */
  router.get('/trial-balance', 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 = new Date(req.query.periodStart as string);
      const periodEnd = new Date(req.query.periodEnd as string);

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

      const options = {
        projectId: req.query.projectId as string,
        includeZeroBalances: req.query.includeZeroBalances === 'true',
      };

      const report = await reportsService.generateTrialBalance(
        ctx,
        periodStart,
        periodEnd,
        options
      );
      res.json(report);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /account-statement/:accountId
   * Genera estado de cuenta
   */
  router.get('/account-statement/:accountId', 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 = new Date(req.query.periodStart as string);
      const periodEnd = new Date(req.query.periodEnd as string);

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

      const report = await reportsService.generateAccountStatement(
        ctx,
        req.params.accountId,
        periodStart,
        periodEnd
      );
      res.json(report);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

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

      const summary = await reportsService.getFinancialSummary(ctx);
      res.json(summary);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  // ==================== EXPORTACIÓN ====================

  /**
   * GET /export/sap
   * Exporta pólizas para SAP
   */
  router.get('/export/sap', 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 = new Date(req.query.periodStart as string);
      const periodEnd = new Date(req.query.periodEnd as string);

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

      const options = {
        companyCode: req.query.companyCode as string,
        documentType: req.query.documentType as string,
        journalNumber: req.query.journalNumber
          ? parseInt(req.query.journalNumber as string)
          : undefined,
      };

      const result = await integrationService.exportToSAP(ctx, periodStart, periodEnd, options);

      res.setHeader('Content-Type', 'text/plain');
      res.setHeader('Content-Disposition', `attachment; filename="${result.filename}"`);
      res.send(result.data);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /export/contpaqi
   * Exporta pólizas para CONTPAQi
   */
  router.get('/export/contpaqi', 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 = new Date(req.query.periodStart as string);
      const periodEnd = new Date(req.query.periodEnd as string);

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

      const options = {
        polizaTipo: req.query.polizaTipo
          ? parseInt(req.query.polizaTipo as string)
          : undefined,
        diario: req.query.diario ? parseInt(req.query.diario as string) : undefined,
      };

      const result = await integrationService.exportToCONTPAQi(
        ctx,
        periodStart,
        periodEnd,
        options
      );

      res.setHeader('Content-Type', 'text/plain');
      res.setHeader('Content-Disposition', `attachment; filename="${result.filename}"`);
      res.send(result.data);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /export/cfdi-polizas
   * Exporta pólizas en formato CFDI
   */
  router.get('/export/cfdi-polizas', 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 = new Date(req.query.periodStart as string);
      const periodEnd = new Date(req.query.periodEnd as string);

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

      const options = {
        tipoSolicitud: req.query.tipoSolicitud as string,
        numOrden: req.query.numOrden as string,
        numTramite: req.query.numTramite as string,
      };

      const result = await integrationService.exportCFDIPolizas(
        ctx,
        periodStart,
        periodEnd,
        options
      );

      res.setHeader('Content-Type', 'application/xml');
      res.setHeader('Content-Disposition', `attachment; filename="${result.filename}"`);
      res.send(result.data);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /export/chart-of-accounts
   * Exporta catálogo de cuentas
   */
  router.get('/export/chart-of-accounts', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const format = (req.query.format as 'csv' | 'xml' | 'json') || 'csv';
      const result = await integrationService.exportChartOfAccounts(ctx, format);

      const contentType =
        format === 'xml'
          ? 'application/xml'
          : format === 'json'
            ? 'application/json'
            : 'text/csv';

      res.setHeader('Content-Type', contentType);
      res.setHeader('Content-Disposition', `attachment; filename="${result.filename}"`);
      res.send(typeof result.data === 'object' ? JSON.stringify(result.data, null, 2) : result.data);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /export/trial-balance
   * Exporta balanza de comprobación
   */
  router.get('/export/trial-balance', 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 = new Date(req.query.periodStart as string);
      const periodEnd = new Date(req.query.periodEnd as string);

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

      const format = (req.query.format as 'csv' | 'xml' | 'json') || 'csv';
      const result = await integrationService.exportTrialBalance(
        ctx,
        periodStart,
        periodEnd,
        format
      );

      const contentType =
        format === 'xml'
          ? 'application/xml'
          : format === 'json'
            ? 'application/json'
            : 'text/csv';

      res.setHeader('Content-Type', contentType);
      res.setHeader('Content-Disposition', `attachment; filename="${result.filename}"`);
      res.send(typeof result.data === 'object' ? JSON.stringify(result.data, null, 2) : result.data);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  // ==================== IMPORTACIÓN ====================

  /**
   * POST /import/chart-of-accounts
   * Importa catálogo de cuentas
   */
  router.post('/import/chart-of-accounts', 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 { data, format } = req.body;
      if (!data || !format) {
        res.status(400).json({ error: 'Se requieren datos y formato' });
        return;
      }

      const result = await integrationService.importChartOfAccounts(ctx, data, format);
      res.json(result);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  return router;
}
