/**
 * Partner Segment Controller
 * API endpoints para gestion de segmentos de partners
 *
 * @module Partners
 * @prefix /api/v1/partner-segments
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import {
  PartnerSegmentService,
  CreatePartnerSegmentDto,
  UpdatePartnerSegmentDto,
  PartnerSegmentFilters,
  ServiceContext,
} from '../services/partner-segment.service';

export function createPartnerSegmentController(dataSource: DataSource): Router {
  const router = Router();
  const segmentService = new PartnerSegmentService(dataSource);

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

  /**
   * Validate tenant header
   */
  function validateTenant(req: Request, res: Response): boolean {
    const tenantId = req.headers['x-tenant-id'];
    if (!tenantId) {
      res.status(400).json({ success: false, error: 'X-Tenant-Id header required' });
      return false;
    }
    return true;
  }

  /**
   * GET /api/v1/partner-segments
   * Lista todos los segmentos con filtros
   */
  router.get('/', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const { segmentType, isActive, search } = req.query;

      const filters: PartnerSegmentFilters = {};
      if (segmentType) filters.segmentType = segmentType as any;
      if (isActive !== undefined) filters.isActive = isActive === 'true';
      if (search) filters.search = search as string;

      const segments = await segmentService.findAll(ctx, filters);
      return res.json({ success: true, data: segments, count: segments.length });
    } catch (error) {
      return next(error);
    }
  });

  /**
   * GET /api/v1/partner-segments/customers
   * Lista segmentos activos para clientes
   */
  router.get('/customers', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const segments = await segmentService.findCustomerSegments(ctx);
      return res.json({ success: true, data: segments, count: segments.length });
    } catch (error) {
      return next(error);
    }
  });

  /**
   * GET /api/v1/partner-segments/suppliers
   * Lista segmentos activos para proveedores
   */
  router.get('/suppliers', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const segments = await segmentService.findSupplierSegments(ctx);
      return res.json({ success: true, data: segments, count: segments.length });
    } catch (error) {
      return next(error);
    }
  });

  /**
   * GET /api/v1/partner-segments/statistics
   * Estadisticas de segmentos
   */
  router.get('/statistics', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const stats = await segmentService.getStatistics(ctx);
      return res.json({ success: true, data: stats });
    } catch (error) {
      return next(error);
    }
  });

  /**
   * GET /api/v1/partner-segments/:id
   * Obtiene un segmento por ID
   */
  router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const segment = await segmentService.findById(ctx, req.params.id);
      if (!segment) {
        return res.status(404).json({ success: false, error: 'Segmento no encontrado' });
      }

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

  /**
   * POST /api/v1/partner-segments
   * Crea un nuevo segmento
   */
  router.post('/', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const dto: CreatePartnerSegmentDto = req.body;

      // Validate required fields
      if (!dto.code || !dto.name || !dto.segmentType) {
        return res.status(400).json({
          success: false,
          error: 'code, name y segmentType son requeridos',
        });
      }

      // Validate segmentType
      if (!['customer', 'supplier', 'both'].includes(dto.segmentType)) {
        return res.status(400).json({
          success: false,
          error: 'segmentType debe ser customer, supplier o both',
        });
      }

      const segment = await segmentService.create(ctx, dto);
      return res.status(201).json({ success: true, data: segment });
    } catch (error: any) {
      if (error.message?.includes('already exists')) {
        return res.status(409).json({ success: false, error: error.message });
      }
      return next(error);
    }
  });

  /**
   * PATCH /api/v1/partner-segments/:id
   * Actualiza un segmento
   */
  router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const dto: UpdatePartnerSegmentDto = req.body;
      const segment = await segmentService.update(ctx, req.params.id, dto);

      if (!segment) {
        return res.status(404).json({ success: false, error: 'Segmento no encontrado' });
      }

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

  /**
   * PATCH /api/v1/partner-segments/:id/activate
   * Activa un segmento
   */
  router.patch('/:id/activate', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const segment = await segmentService.activate(ctx, req.params.id);
      if (!segment) {
        return res.status(404).json({ success: false, error: 'Segmento no encontrado' });
      }

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

  /**
   * PATCH /api/v1/partner-segments/:id/deactivate
   * Desactiva un segmento
   */
  router.patch('/:id/deactivate', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const segment = await segmentService.deactivate(ctx, req.params.id);
      if (!segment) {
        return res.status(404).json({ success: false, error: 'Segmento no encontrado' });
      }

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

  /**
   * PUT /api/v1/partner-segments/reorder
   * Reordena los segmentos
   */
  router.put('/reorder', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const { orderedIds } = req.body;
      if (!orderedIds || !Array.isArray(orderedIds)) {
        return res.status(400).json({
          success: false,
          error: 'orderedIds debe ser un array de IDs',
        });
      }

      const segments = await segmentService.reorder(ctx, orderedIds);
      return res.json({ success: true, data: segments });
    } catch (error) {
      return next(error);
    }
  });

  /**
   * DELETE /api/v1/partner-segments/:id
   * Elimina un segmento
   */
  router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const deleted = await segmentService.delete(ctx, req.params.id);
      if (!deleted) {
        return res.status(404).json({ success: false, error: 'Segmento no encontrado' });
      }

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

  return router;
}

export default createPartnerSegmentController;
