/**
 * BranchPaymentTerminal Controller
 * API endpoints para gestión de terminales de pago por sucursal
 *
 * @module Branches
 * @prefix /api/v1/branches/:branchId/payment-terminals
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  BranchPaymentTerminalService,
  CreateBranchPaymentTerminalDto,
  UpdateBranchPaymentTerminalDto,
} from '../services/branch-payment-terminal.service';
import { ServiceContext } from '../services/branch.service';
import { HealthStatus } from '../entities/branch-payment-terminal.entity';

const router = Router({ mergeParams: true });
const terminalService = new BranchPaymentTerminalService();

/**
 * Helper to extract ServiceContext from request
 */
function getContext(req: Request): ServiceContext {
  return {
    tenantId: req.headers['x-tenant-id'] as string,
    userId: (req as any).user?.id,
  };
}

/**
 * GET /api/v1/branches/:branchId/payment-terminals
 * Lista todas las terminales de pago de una sucursal
 */
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { branchId } = req.params;
    const { terminalProvider, isActive, healthStatus } = req.query;

    const terminals = await terminalService.findAll(getContext(req), {
      branchId,
      terminalProvider: terminalProvider as any,
      isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
      healthStatus: healthStatus as HealthStatus,
    });

    return res.json({
      success: true,
      data: terminals,
      count: terminals.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/:branchId/payment-terminals/primary
 * Obtiene la terminal primaria de una sucursal
 */
router.get('/primary', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { branchId } = req.params;
    const terminal = await terminalService.findPrimaryTerminal(getContext(req), branchId);

    if (!terminal) {
      return res.status(404).json({ error: 'No hay terminal primaria configurada' });
    }

    return res.json({ success: true, data: terminal });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/:branchId/payment-terminals/health
 * Obtiene el resumen de salud de las terminales
 */
router.get('/health', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const summary = await terminalService.getHealthSummary(getContext(req));
    return res.json({ success: true, data: summary });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/:branchId/payment-terminals/needs-check
 * Obtiene las terminales que necesitan health check
 */
router.get('/needs-check', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { maxAgeMinutes } = req.query;
    const terminals = await terminalService.getTerminalsNeedingHealthCheck(
      getContext(req),
      maxAgeMinutes ? parseInt(maxAgeMinutes as string) : undefined
    );

    return res.json({ success: true, data: terminals, count: terminals.length });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/:branchId/payment-terminals/:id
 * Obtiene una terminal específica
 */
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const terminal = await terminalService.findById(getContext(req), req.params.id);
    if (!terminal) {
      return res.status(404).json({ error: 'Terminal no encontrada' });
    }

    return res.json({ success: true, data: terminal });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/branches/:branchId/payment-terminals
 * Crea una nueva terminal de pago
 */
router.post('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { branchId } = req.params;
    const data: CreateBranchPaymentTerminalDto = {
      ...req.body,
      branchId,
    };

    // Validate required fields
    if (!data.terminalId || !data.terminalProvider || !data.provider) {
      return res.status(400).json({
        error: 'terminalId, terminalProvider y provider son requeridos',
      });
    }

    // Check if terminal ID already exists
    const existing = await terminalService.findByTerminalId(getContext(req), data.terminalId);
    if (existing) {
      return res.status(409).json({ error: 'Ya existe una terminal con ese ID' });
    }

    const terminal = await terminalService.create(getContext(req), data);
    return res.status(201).json({ success: true, data: terminal });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/branches/:branchId/payment-terminals/:id
 * Actualiza una terminal
 */
router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: UpdateBranchPaymentTerminalDto = req.body;
    const terminal = await terminalService.update(getContext(req), req.params.id, data);

    if (!terminal) {
      return res.status(404).json({ error: 'Terminal no encontrada' });
    }

    return res.json({ success: true, data: terminal });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/branches/:branchId/payment-terminals/:id/set-primary
 * Establece una terminal como primaria
 */
router.post('/:id/set-primary', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const terminal = await terminalService.setAsPrimary(getContext(req), req.params.id);
    if (!terminal) {
      return res.status(404).json({ error: 'Terminal no encontrada' });
    }

    return res.json({
      success: true,
      data: terminal,
      message: 'Terminal establecida como primaria',
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/branches/:branchId/payment-terminals/:id/health-check
 * Actualiza el estado de salud de una terminal
 */
router.post('/:id/health-check', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { healthStatus } = req.body;
    if (!healthStatus) {
      return res.status(400).json({ error: 'healthStatus es requerido' });
    }

    const terminal = await terminalService.updateHealthStatus(
      getContext(req),
      req.params.id,
      healthStatus as HealthStatus
    );

    if (!terminal) {
      return res.status(404).json({ error: 'Terminal no encontrada' });
    }

    return res.json({ success: true, data: terminal });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/branches/:branchId/payment-terminals/:id/record-transaction
 * Registra una transacción en la terminal
 */
router.post('/:id/record-transaction', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const terminal = await terminalService.recordTransaction(getContext(req), req.params.id);
    if (!terminal) {
      return res.status(404).json({ error: 'Terminal no encontrada' });
    }

    return res.json({ success: true, data: terminal });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/branches/:branchId/payment-terminals/:id
 * Elimina una terminal
 */
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const deleted = await terminalService.delete(getContext(req), req.params.id);
    if (!deleted) {
      return res.status(404).json({ error: 'Terminal no encontrada' });
    }

    return res.json({ success: true, message: 'Terminal eliminada' });
  } catch (error) {
    return next(error);
  }
});

export default router;
