import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { AuthenticatedRequest } from '../../shared/types/index.js';
import { rankingService, ABCClassification } from './ranking.service.js';

// ============================================================================
// VALIDATION SCHEMAS
// ============================================================================

const calculateRankingsSchema = z.object({
  company_id: z.string().uuid().optional(),
  period_start: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  period_end: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
});

const rankingFiltersSchema = z.object({
  company_id: z.string().uuid().optional(),
  period_start: z.string().optional(),
  period_end: z.string().optional(),
  customer_abc: z.enum(['A', 'B', 'C']).optional(),
  supplier_abc: z.enum(['A', 'B', 'C']).optional(),
  min_sales: z.coerce.number().min(0).optional(),
  min_purchases: z.coerce.number().min(0).optional(),
  page: z.coerce.number().min(1).default(1),
  limit: z.coerce.number().min(1).max(100).default(20),
});

// ============================================================================
// CONTROLLER
// ============================================================================

class RankingController {
  /**
   * POST /rankings/calculate
   * Calculate partner rankings
   */
  async calculateRankings(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const { company_id, period_start, period_end } = calculateRankingsSchema.parse(req.body);
      const tenantId = req.user!.tenantId;

      const result = await rankingService.calculateRankings(
        tenantId,
        company_id,
        period_start,
        period_end
      );

      res.json({
        success: true,
        message: 'Rankings calculados exitosamente',
        data: result,
      });
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /rankings
   * List all rankings with filters
   */
  async findRankings(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const filters = rankingFiltersSchema.parse(req.query);
      const tenantId = req.user!.tenantId;

      const { data, total } = await rankingService.findRankings(tenantId, filters);

      res.json({
        success: true,
        data,
        pagination: {
          page: filters.page,
          limit: filters.limit,
          total,
          totalPages: Math.ceil(total / filters.limit),
        },
      });
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /rankings/partner/:partnerId
   * Get ranking for a specific partner
   */
  async findPartnerRanking(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const { partnerId } = req.params;
      const { period_start, period_end } = req.query as {
        period_start?: string;
        period_end?: string;
      };
      const tenantId = req.user!.tenantId;

      const ranking = await rankingService.findPartnerRanking(
        partnerId,
        tenantId,
        period_start,
        period_end
      );

      if (!ranking) {
        res.status(404).json({
          success: false,
          error: 'No se encontró ranking para este contacto',
        });
        return;
      }

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

  /**
   * GET /rankings/partner/:partnerId/history
   * Get ranking history for a partner
   */
  async getPartnerHistory(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const { partnerId } = req.params;
      const limit = parseInt(req.query.limit as string) || 12;
      const tenantId = req.user!.tenantId;

      const history = await rankingService.getPartnerRankingHistory(
        partnerId,
        tenantId,
        Math.min(limit, 24)
      );

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

  /**
   * GET /rankings/top/customers
   * Get top customers
   */
  async getTopCustomers(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const limit = parseInt(req.query.limit as string) || 10;
      const tenantId = req.user!.tenantId;

      const data = await rankingService.getTopPartners(
        tenantId,
        'customers',
        Math.min(limit, 50)
      );

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

  /**
   * GET /rankings/top/suppliers
   * Get top suppliers
   */
  async getTopSuppliers(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const limit = parseInt(req.query.limit as string) || 10;
      const tenantId = req.user!.tenantId;

      const data = await rankingService.getTopPartners(
        tenantId,
        'suppliers',
        Math.min(limit, 50)
      );

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

  /**
   * GET /rankings/abc/customers
   * Get ABC distribution for customers
   */
  async getCustomerABCDistribution(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const { company_id } = req.query as { company_id?: string };
      const tenantId = req.user!.tenantId;

      const distribution = await rankingService.getABCDistribution(
        tenantId,
        'customers',
        company_id
      );

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

  /**
   * GET /rankings/abc/suppliers
   * Get ABC distribution for suppliers
   */
  async getSupplierABCDistribution(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const { company_id } = req.query as { company_id?: string };
      const tenantId = req.user!.tenantId;

      const distribution = await rankingService.getABCDistribution(
        tenantId,
        'suppliers',
        company_id
      );

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

  /**
   * GET /rankings/abc/customers/:abc
   * Get customers by ABC classification
   */
  async getCustomersByABC(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const abc = req.params.abc.toUpperCase() as ABCClassification;
      const page = parseInt(req.query.page as string) || 1;
      const limit = parseInt(req.query.limit as string) || 20;
      const tenantId = req.user!.tenantId;

      if (!['A', 'B', 'C'].includes(abc || '')) {
        res.status(400).json({
          success: false,
          error: 'Clasificación ABC inválida. Use A, B o C.',
        });
        return;
      }

      const { data, total } = await rankingService.findPartnersByABC(
        tenantId,
        abc,
        'customers',
        page,
        Math.min(limit, 100)
      );

      res.json({
        success: true,
        data,
        pagination: {
          page,
          limit,
          total,
          totalPages: Math.ceil(total / limit),
        },
      });
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /rankings/abc/suppliers/:abc
   * Get suppliers by ABC classification
   */
  async getSuppliersByABC(
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> {
    try {
      const abc = req.params.abc.toUpperCase() as ABCClassification;
      const page = parseInt(req.query.page as string) || 1;
      const limit = parseInt(req.query.limit as string) || 20;
      const tenantId = req.user!.tenantId;

      if (!['A', 'B', 'C'].includes(abc || '')) {
        res.status(400).json({
          success: false,
          error: 'Clasificación ABC inválida. Use A, B o C.',
        });
        return;
      }

      const { data, total } = await rankingService.findPartnersByABC(
        tenantId,
        abc,
        'suppliers',
        page,
        Math.min(limit, 100)
      );

      res.json({
        success: true,
        data,
        pagination: {
          page,
          limit,
          total,
          totalPages: Math.ceil(total / limit),
        },
      });
    } catch (error) {
      next(error);
    }
  }
}

export const rankingController = new RankingController();
