/**
 * ARController - Controlador de Cuentas por Cobrar
 *
 * Endpoints para cuentas por cobrar y cobranza.
 *
 * @module Finance
 */

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

export function createARController(dataSource: DataSource): Router {
  const router = Router();
  const service = new ARService(dataSource);

  // ==================== CUENTAS POR COBRAR ====================

  /**
   * GET /
   * Lista cuentas por cobrar 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,
        status: req.query.status as any,
        partnerId: req.query.partnerId as string,
        projectId: req.query.projectId as string,
        startDate: req.query.startDate ? new Date(req.query.startDate as string) : undefined,
        endDate: req.query.endDate ? new Date(req.query.endDate as string) : undefined,
        overdue: req.query.overdue === 'true',
        search: req.query.search as string,
      };

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

  /**
   * GET /dashboard
   * Obtiene estadísticas 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 stats = await service.getDashboardStats(ctx);
      res.json(stats);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

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

      const options = {
        partnerId: req.query.partnerId as string,
        projectId: req.query.projectId as string,
        asOfDate: req.query.asOfDate ? new Date(req.query.asOfDate as string) : undefined,
      };

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

  /**
   * GET /collection-forecast
   * Obtiene pronóstico de cobranza
   */
  router.get('/collection-forecast', 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 = {
        partnerId: req.query.partnerId as string,
        projectId: req.query.projectId as string,
      };

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

  /**
   * GET /:id
   * Obtiene una cuenta por cobrar 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 ar = await service.findById(ctx, req.params.id);
      if (!ar) {
        res.status(404).json({ error: 'Cuenta por cobrar no encontrada' });
        return;
      }

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

  /**
   * POST /
   * Crea una nueva cuenta por cobrar
   */
  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 ar = await service.create(ctx, req.body);
      res.status(201).json(ar);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * PUT /:id
   * Actualiza una cuenta por cobrar
   */
  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 ar = await service.update(ctx, req.params.id, req.body);
      res.json(ar);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /:id/cancel
   * Cancela una cuenta por cobrar
   */
  router.post('/:id/cancel', 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 { reason } = req.body;
      if (!reason) {
        res.status(400).json({ error: 'Se requiere motivo de cancelación' });
        return;
      }

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

  /**
   * POST /:id/write-off
   * Castiga una cuenta por cobrar
   */
  router.post('/:id/write-off', 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 { reason } = req.body;
      if (!reason) {
        res.status(400).json({ error: 'Se requiere motivo de castigo' });
        return;
      }

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

  /**
   * POST /:id/collection-attempt
   * Registra intento de cobranza
   */
  router.post('/:id/collection-attempt', 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 { notes } = req.body;
      if (!notes) {
        res.status(400).json({ error: 'Se requieren notas de la gestión' });
        return;
      }

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

  // ==================== COBROS ====================

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

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

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

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

  /**
   * POST /collections/:id/cancel
   * Cancela un cobro
   */
  router.post('/collections/:id/cancel', 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 { reason } = req.body;
      if (!reason) {
        res.status(400).json({ error: 'Se requiere motivo de cancelación' });
        return;
      }

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

  return router;
}
