/**
 * KpiConfigController - Controlador de KPIs Configurables
 *
 * Endpoints para gestion de KPIs dinamicos con formulas configurables.
 *
 * @module Reports (MAI-006)
 * @gap GAP-001
 */

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

export function createKpiConfigController(dataSource: DataSource): Router {
  const router = Router();
  const service = new KpiConfigService(dataSource);

  // ==================== KPI CONFIGS ====================

  /**
   * GET /
   * Lista KPIs configurados con filtros
   */
  router.get('/', async (req: Request, res: Response, _next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const filters = {
        category: req.query.category as any,
        module: req.query.module as string,
        isActive: req.query.isActive === 'true' ? true : req.query.isActive === 'false' ? false : undefined,
        search: req.query.search as string,
      };

      const pagination = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 20,
      };

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

  /**
   * GET /dashboard
   * Obtiene KPIs con sus ultimos valores para dashboard
   */
  router.get('/dashboard', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const projectId = req.query.projectId as string | undefined;

      const dashboard = await service.getKpiDashboard(tenantId, projectId);
      res.json(dashboard);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /by-category/:category
   * Lista KPIs por categoria
   */
  router.get('/by-category/:category', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { category } = req.params;

      const kpis = await service.getByCategory(tenantId, category as any);
      res.json(kpis);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /by-module/:module
   * Lista KPIs por modulo
   */
  router.get('/by-module/:module', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { module } = req.params;

      const kpis = await service.getByModule(tenantId, module);
      res.json(kpis);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /code/:code
   * Obtiene KPI por codigo
   */
  router.get('/code/:code', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { code } = req.params;

      const kpi = await service.findByCode(tenantId, code);
      if (!kpi) {
        res.status(404).json({ error: 'KPI no encontrado' });
        return;
      }
      res.json(kpi);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /:id
   * Obtiene KPI por ID
   */
  router.get('/:id', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { id } = req.params;

      const kpi = await service.findById(tenantId, id);
      if (!kpi) {
        res.status(404).json({ error: 'KPI no encontrado' });
        return;
      }
      res.json(kpi);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /
   * Crea un nuevo KPI
   */
  router.post('/', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;

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

  /**
   * PUT /:id
   * Actualiza un KPI
   */
  router.put('/:id', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;
      const { id } = req.params;

      const kpi = await service.update(tenantId, id, req.body, userId);
      if (!kpi) {
        res.status(404).json({ error: 'KPI no encontrado' });
        return;
      }
      res.json(kpi);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * DELETE /:id
   * Elimina un KPI (soft delete)
   */
  router.delete('/:id', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;
      const { id } = req.params;

      const deleted = await service.delete(tenantId, id, userId);
      if (!deleted) {
        res.status(404).json({ error: 'KPI no encontrado' });
        return;
      }
      res.status(204).send();
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  // ==================== KPI VALUES ====================

  /**
   * GET /:id/values
   * Lista valores historicos de un KPI
   */
  router.get('/:id/values', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { id } = req.params;

      const filters = {
        kpiId: id,
        projectId: req.query.projectId as string | undefined,
        periodType: req.query.periodType as any,
        fromDate: req.query.fromDate ? new Date(req.query.fromDate as string) : undefined,
        toDate: req.query.toDate ? new Date(req.query.toDate as string) : undefined,
      };

      const pagination = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 50,
      };

      const result = await service.getValues(tenantId, filters, pagination);
      res.json(result);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /:id/latest
   * Obtiene el ultimo valor de un KPI
   */
  router.get('/:id/latest', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { id } = req.params;
      const projectId = req.query.projectId as string | undefined;

      const value = await service.getLatestValue(tenantId, id, projectId);
      if (!value) {
        res.status(404).json({ error: 'No hay valores registrados para este KPI' });
        return;
      }
      res.json(value);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /values
   * Registra un nuevo valor de KPI
   */
  router.post('/values', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;

      const value = await service.recordValue(tenantId, req.body, userId);
      res.status(201).json(value);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  return router;
}
