import { useMemo } from "react";
import { StockLevelDto, ArticleDto, ValuationMethod } from "../types";

interface StockSummary {
  totalQuantity: number;
  totalValue: number;
  averageCost: number;
  articleCount: number;
  lowStockCount: number;
  outOfStockCount: number;
}

interface ArticleStockInfo {
  totalQuantity: number;
  totalValue: number;
  availableQuantity: number;
  reservedQuantity: number;
  warehouseBreakdown: {
    warehouseId: number;
    warehouseName: string;
    quantity: number;
    value: number;
  }[];
}

/**
 * Hook for stock calculations and aggregations
 */
export function useStockCalculations(stockLevels: StockLevelDto[] | undefined) {
  const summary = useMemo<StockSummary>(() => {
    if (!stockLevels || stockLevels.length === 0) {
      return {
        totalQuantity: 0,
        totalValue: 0,
        averageCost: 0,
        articleCount: 0,
        lowStockCount: 0,
        outOfStockCount: 0,
      };
    }

    const articleIds = new Set<number>();
    let totalQuantity = 0;
    let totalValue = 0;
    let lowStockCount = 0;
    let outOfStockCount = 0;

    for (const level of stockLevels) {
      articleIds.add(level.articleId);
      totalQuantity += level.quantity;
      totalValue += level.stockValue || 0;

      if (level.quantity <= 0) {
        outOfStockCount++;
      } else if (level.isLowStock) {
        lowStockCount++;
      }
    }

    return {
      totalQuantity,
      totalValue,
      averageCost: totalQuantity > 0 ? totalValue / totalQuantity : 0,
      articleCount: articleIds.size,
      lowStockCount,
      outOfStockCount,
    };
  }, [stockLevels]);

  const getArticleStock = useMemo(() => {
    return (articleId: number): ArticleStockInfo => {
      if (!stockLevels) {
        return {
          totalQuantity: 0,
          totalValue: 0,
          availableQuantity: 0,
          reservedQuantity: 0,
          warehouseBreakdown: [],
        };
      }

      const articleLevels = stockLevels.filter(
        (l) => l.articleId === articleId,
      );

      let totalQuantity = 0;
      let totalValue = 0;
      let reservedQuantity = 0;
      const warehouseBreakdown: ArticleStockInfo["warehouseBreakdown"] = [];

      for (const level of articleLevels) {
        totalQuantity += level.quantity;
        totalValue += level.stockValue || 0;
        reservedQuantity += level.reservedQuantity;

        warehouseBreakdown.push({
          warehouseId: level.warehouseId,
          warehouseName:
            level.warehouseName || `Magazzino ${level.warehouseId}`,
          quantity: level.quantity,
          value: level.stockValue || 0,
        });
      }

      return {
        totalQuantity,
        totalValue,
        availableQuantity: totalQuantity - reservedQuantity,
        reservedQuantity,
        warehouseBreakdown,
      };
    };
  }, [stockLevels]);

  const groupByWarehouse = useMemo(() => {
    if (!stockLevels) return new Map<number, StockLevelDto[]>();

    const grouped = new Map<number, StockLevelDto[]>();
    for (const level of stockLevels) {
      const existing = grouped.get(level.warehouseId) || [];
      existing.push(level);
      grouped.set(level.warehouseId, existing);
    }
    return grouped;
  }, [stockLevels]);

  return {
    summary,
    getArticleStock,
    groupByWarehouse,
  };
}

/**
 * Calculate valuation based on method
 */
export function calculateValuation(
  movements: { quantity: number; unitCost: number; date: string }[],
  method: ValuationMethod,
  targetQuantity: number,
): { totalCost: number; averageCost: number } {
  if (targetQuantity <= 0 || movements.length === 0) {
    return { totalCost: 0, averageCost: 0 };
  }

  // Sort movements by date
  const sorted = [...movements].sort(
    (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
  );

  switch (method) {
    case ValuationMethod.WeightedAverage: {
      let totalQty = 0;
      let totalCost = 0;
      for (const m of sorted) {
        totalQty += m.quantity;
        totalCost += m.quantity * m.unitCost;
      }
      const avgCost = totalQty > 0 ? totalCost / totalQty : 0;
      return {
        totalCost: targetQuantity * avgCost,
        averageCost: avgCost,
      };
    }

    case ValuationMethod.FIFO: {
      // First In, First Out
      let remaining = targetQuantity;
      let totalCost = 0;
      for (const m of sorted) {
        if (remaining <= 0) break;
        const take = Math.min(remaining, m.quantity);
        totalCost += take * m.unitCost;
        remaining -= take;
      }
      return {
        totalCost,
        averageCost: targetQuantity > 0 ? totalCost / targetQuantity : 0,
      };
    }

    case ValuationMethod.LIFO: {
      // Last In, First Out
      const reversed = [...sorted].reverse();
      let remaining = targetQuantity;
      let totalCost = 0;
      for (const m of reversed) {
        if (remaining <= 0) break;
        const take = Math.min(remaining, m.quantity);
        totalCost += take * m.unitCost;
        remaining -= take;
      }
      return {
        totalCost,
        averageCost: targetQuantity > 0 ? totalCost / targetQuantity : 0,
      };
    }

    case ValuationMethod.StandardCost: {
      // Use the most recent cost as standard
      const lastMovement = sorted[sorted.length - 1];
      const standardCost = lastMovement?.unitCost || 0;
      return {
        totalCost: targetQuantity * standardCost,
        averageCost: standardCost,
      };
    }

    case ValuationMethod.SpecificCost: {
      // Specific cost requires batch/serial tracking
      // For now, fall back to weighted average
      let totalQty = 0;
      let totalCost = 0;
      for (const m of sorted) {
        totalQty += m.quantity;
        totalCost += m.quantity * m.unitCost;
      }
      const avgCost = totalQty > 0 ? totalCost / totalQty : 0;
      return {
        totalCost: targetQuantity * avgCost,
        averageCost: avgCost,
      };
    }

    default:
      return { totalCost: 0, averageCost: 0 };
  }
}

/**
 * Hook for article availability check
 */
export function useArticleAvailability(
  article: ArticleDto | undefined,
  stockLevels: StockLevelDto[] | undefined,
  requestedQuantity: number,
  warehouseId?: number,
) {
  return useMemo(() => {
    if (!article || !stockLevels) {
      return {
        isAvailable: false,
        availableQuantity: 0,
        shortageQuantity: requestedQuantity,
        message: "Dati non disponibili",
      };
    }

    const relevantLevels = warehouseId
      ? stockLevels.filter(
          (l) => l.articleId === article.id && l.warehouseId === warehouseId,
        )
      : stockLevels.filter((l) => l.articleId === article.id);

    const totalAvailable = relevantLevels.reduce(
      (sum, l) =>
        sum + (l.availableQuantity || l.quantity - l.reservedQuantity),
      0,
    );

    const isAvailable = totalAvailable >= requestedQuantity;
    const shortageQuantity = Math.max(0, requestedQuantity - totalAvailable);

    let message: string;
    if (isAvailable) {
      message = `Disponibile: ${totalAvailable} ${article.unitOfMeasure}`;
    } else if (totalAvailable > 0) {
      message = `Disponibile parzialmente: ${totalAvailable} ${article.unitOfMeasure} (mancano ${shortageQuantity})`;
    } else {
      message = "Non disponibile";
    }

    return {
      isAvailable,
      availableQuantity: totalAvailable,
      shortageQuantity,
      message,
    };
  }, [article, stockLevels, requestedQuantity, warehouseId]);
}
