/**
 * BankReconciliationController - Controlador de Conciliación Bancaria
 *
 * Endpoints para cuentas bancarias, movimientos y conciliación.
 *
 * @module Finance
 */

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

export function createBankReconciliationController(dataSource: DataSource): Router {
  const router = Router();
  const service = new BankReconciliationService(dataSource);

  // ==================== CUENTAS BANCARIAS ====================

  /**
   * GET /accounts
   * Lista cuentas bancarias
   */
  router.get('/accounts', 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,
        accountType: req.query.accountType as any,
        status: req.query.status as any,
        projectId: req.query.projectId as string,
        search: req.query.search as string,
      };

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

  /**
   * GET /accounts/summary
   * Obtiene resumen de saldos
   */
  router.get('/accounts/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 service.getBankAccountSummary(ctx);
      res.json(summary);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

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

      const account = await service.findAccountById(ctx, req.params.id);
      if (!account) {
        return res.status(404).json({ error: 'Cuenta bancaria no encontrada' });
      }

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

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

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

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

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

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

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

  // ==================== MOVIMIENTOS ====================

  /**
   * GET /movements
   * Lista movimientos bancarios
   */
  router.get('/movements', 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) || 50,
        bankAccountId: req.query.bankAccountId as string,
        movementType: req.query.movementType as any,
        status: req.query.status as any,
        startDate: req.query.startDate ? new Date(req.query.startDate as string) : undefined,
        endDate: req.query.endDate ? new Date(req.query.endDate as string) : undefined,
        search: req.query.search as string,
      };

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

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

      const movement = await service.findMovementById(ctx, req.params.id);
      if (!movement) {
        return res.status(404).json({ error: 'Movimiento no encontrado' });
      }

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

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

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

  /**
   * POST /movements/import
   * Importa estado de cuenta
   */
  router.post('/movements/import', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

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

  /**
   * POST /movements/:id/match
   * Asocia movimiento con pago/cobro
   */
  router.post('/movements/:id/match', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

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

  /**
   * POST /movements/:id/ignore
   * Marca movimiento como ignorado
   */
  router.post('/movements/:id/ignore', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

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

  // ==================== CONCILIACIÓN ====================

  /**
   * GET /reconciliations
   * Lista conciliaciones
   */
  router.get('/reconciliations', 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,
        bankAccountId: req.query.bankAccountId as string,
        status: req.query.status as any,
      };

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

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

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

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

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

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

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

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

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

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

  /**
   * POST /reconciliations/:id/reconcile-movement
   * Concilia un movimiento
   */
  router.post('/reconciliations/:id/reconcile-movement', async (req: Request, res: Response) => {
    try {
      const ctx = {
        tenantId: req.headers['x-tenant-id'] as string,
        userId: (req as any).user?.id,
      };

      const { movementId } = req.body;
      if (!movementId) {
        return res.status(400).json({ error: 'Se requiere ID del movimiento' });
      }

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

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

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

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

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

  return router;
}
