import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { valuationService, CreateValuationLayerDto } from './valuation.service.js';
import { AuthenticatedRequest, ValidationError, ApiResponse } from '../../shared/types/index.js';

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

const getProductCostSchema = z.object({
  product_id: z.string().uuid(),
  company_id: z.string().uuid(),
});

const createLayerSchema = z.object({
  product_id: z.string().uuid(),
  company_id: z.string().uuid(),
  quantity: z.number().positive(),
  unit_cost: z.number().nonnegative(),
  stock_move_id: z.string().uuid().optional(),
  description: z.string().max(255).optional(),
});

const consumeFifoSchema = z.object({
  product_id: z.string().uuid(),
  company_id: z.string().uuid(),
  quantity: z.number().positive(),
});

const productLayersSchema = z.object({
  company_id: z.string().uuid(),
  include_empty: z.enum(['true', 'false']).optional(),
});

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

class ValuationController {
  /**
   * Get cost for a product based on its valuation method
   * GET /api/inventory/valuation/cost
   */
  async getProductCost(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const validation = getProductCostSchema.safeParse(req.query);
      if (!validation.success) {
        throw new ValidationError('Parámetros inválidos', validation.error.errors);
      }

      const { product_id, company_id } = validation.data;
      const result = await valuationService.getProductCost(
        product_id,
        company_id,
        req.user!.tenantId
      );

      const response: ApiResponse = {
        success: true,
        data: result,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * Get valuation summary for a product
   * GET /api/inventory/valuation/products/:productId/summary
   */
  async getProductSummary(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { productId } = req.params;
      const { company_id } = req.query;

      if (!company_id || typeof company_id !== 'string') {
        throw new ValidationError('company_id es requerido');
      }

      const result = await valuationService.getProductValuationSummary(
        productId,
        company_id,
        req.user!.tenantId
      );

      const response: ApiResponse = {
        success: true,
        data: result,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * Get valuation layers for a product
   * GET /api/inventory/valuation/products/:productId/layers
   */
  async getProductLayers(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { productId } = req.params;
      const validation = productLayersSchema.safeParse(req.query);

      if (!validation.success) {
        throw new ValidationError('Parámetros inválidos', validation.error.errors);
      }

      const { company_id, include_empty } = validation.data;
      const includeEmpty = include_empty === 'true';

      const result = await valuationService.getProductLayers(
        productId,
        company_id,
        req.user!.tenantId,
        includeEmpty
      );

      const response: ApiResponse = {
        success: true,
        data: result,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * Get company-wide valuation report
   * GET /api/inventory/valuation/report
   */
  async getCompanyReport(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { company_id } = req.query;

      if (!company_id || typeof company_id !== 'string') {
        throw new ValidationError('company_id es requerido');
      }

      const result = await valuationService.getCompanyValuationReport(
        company_id,
        req.user!.tenantId
      );

      const response: ApiResponse = {
        success: true,
        data: result,
        meta: {
          total: result.length,
          totalValue: result.reduce((sum, p) => sum + Number(p.total_value), 0),
        },
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * Create a valuation layer manually (for adjustments)
   * POST /api/inventory/valuation/layers
   */
  async createLayer(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const validation = createLayerSchema.safeParse(req.body);
      if (!validation.success) {
        throw new ValidationError('Datos inválidos', validation.error.errors);
      }

      const dto: CreateValuationLayerDto = validation.data;

      const result = await valuationService.createLayer(
        dto,
        req.user!.tenantId,
        req.user!.userId
      );

      const response: ApiResponse = {
        success: true,
        data: result,
        message: 'Capa de valoración creada',
      };

      res.status(201).json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * Consume stock using FIFO (for testing/manual adjustments)
   * POST /api/inventory/valuation/consume
   */
  async consumeFifo(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const validation = consumeFifoSchema.safeParse(req.body);
      if (!validation.success) {
        throw new ValidationError('Datos inválidos', validation.error.errors);
      }

      const { product_id, company_id, quantity } = validation.data;

      const result = await valuationService.consumeFifo(
        product_id,
        company_id,
        quantity,
        req.user!.tenantId,
        req.user!.userId
      );

      const response: ApiResponse = {
        success: true,
        data: result,
        message: `Consumidas ${result.layers_consumed.length} capas FIFO`,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }
}

export const valuationController = new ValuationController();
