/**
 * Partner Controller
 * API endpoints para gestion de socios comerciales
 *
 * @module Partners
 * @prefix /api/v1/partners
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import {
  PartnerService,
  CreatePartnerDto,
  UpdatePartnerDto,
  PartnerFilters,
  ServiceContext,
} from '../services/partner.service';

export function createPartnerController(dataSource: DataSource): Router {
  const router = Router();
  const partnerService = new PartnerService(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/partners
   * Lista todos los partners con filtros y paginacion
   */
  router.get('/', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const {
        partnerType,
        category,
        isActive,
        isVerified,
        salesRepId,
        search,
        minCreditLimit,
        maxCreditLimit,
        page = '1',
        limit = '20',
      } = req.query;

      const filters: PartnerFilters = {};
      if (partnerType) filters.partnerType = partnerType as any;
      if (category) filters.category = category as string;
      if (isActive !== undefined) filters.isActive = isActive === 'true';
      if (isVerified !== undefined) filters.isVerified = isVerified === 'true';
      if (salesRepId) filters.salesRepId = salesRepId as string;
      if (search) filters.search = search as string;
      if (minCreditLimit) filters.minCreditLimit = Number(minCreditLimit);
      if (maxCreditLimit) filters.maxCreditLimit = Number(maxCreditLimit);

      const result = await partnerService.findWithFilters(
        ctx,
        filters,
        Number(page),
        Number(limit)
      );

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

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

      const { page = '1', limit = '20' } = req.query;
      const result = await partnerService.findCustomers(ctx, Number(page), Number(limit));

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

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

      const { page = '1', limit = '20' } = req.query;
      const result = await partnerService.findSuppliers(ctx, Number(page), Number(limit));

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

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

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

  /**
   * GET /api/v1/partners/categories
   * Lista categorias disponibles
   */
  router.get('/categories', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const categories = await partnerService.getCategories(ctx);
      return res.json({ success: true, data: categories });
    } catch (error) {
      return next(error);
    }
  });

  /**
   * GET /api/v1/partners/search
   * Busqueda rapida de partners
   */
  router.get('/search', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const { q, limit = '10' } = req.query;
      if (!q) {
        return res.status(400).json({ success: false, error: 'Query parameter q is required' });
      }

      const partners = await partnerService.search(ctx, q as string, Number(limit));
      return res.json({ success: true, data: partners });
    } catch (error) {
      return next(error);
    }
  });

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

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

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

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

      const dto: CreatePartnerDto = req.body;

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

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

      const partner = await partnerService.create(ctx, dto);
      return res.status(201).json({ success: true, data: partner });
    } 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/partners/:id
   * Actualiza un partner
   */
  router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const dto: UpdatePartnerDto = req.body;
      const partner = await partnerService.update(ctx, req.params.id, dto);

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

      return res.json({ success: true, data: partner });
    } 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/partners/:id/verify
   * Marca un partner como verificado
   */
  router.patch('/:id/verify', async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!validateTenant(req, res)) return;
      const ctx = getContext(req);

      const partner = await partnerService.verify(ctx, req.params.id);
      if (!partner) {
        return res.status(404).json({ success: false, error: 'Partner no encontrado' });
      }

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

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

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

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

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

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

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

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

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

      return res.json({ success: true, message: 'Partner eliminado' });
    } catch (error: any) {
      if (error.message?.includes('Cannot delete')) {
        return res.status(400).json({ success: false, error: error.message });
      }
      return next(error);
    }
  });

  return router;
}

export default createPartnerController;
