"use client";

import { useState, useEffect, useMemo, useCallback } from "react";
import { useProductStore } from "@/zustand/productStore";
import { useProductData } from "@/lib/hooks/useProductData";
import { useEstimatedDate } from "@/lib/hooks/useEstimatedDate";
import { ProductOptionDataModel, VariantGroup } from "@/lib/types/models";
import { computeTierPrice } from "@/lib/utils/orderPricing";

function getSkuAttributes(product: ProductOptionDataModel): Record<string, string> {
  const map: Record<string, string> = {};
  (product?.options || []).forEach((opt) => {
    const variantId = opt.variantItemId?.variantId?._id;
    const itemId = opt.variantItemId?.attributeItemId?._id;
    if (variantId && itemId) {
      map[String(variantId)] = String(itemId);
    }
  });
  return map;
}

function resolveSelections(
  desiredSelections: Record<string, string>,
  variantGroups: VariantGroup[],
  productData: ProductOptionDataModel[]
): { selections: Record<string, string>; visibleVariantGroups: VariantGroup[] } {
  if (!productData || productData.length === 0 || !variantGroups || variantGroups.length === 0) {
    return { selections: desiredSelections, visibleVariantGroups: variantGroups || [] };
  }

  const nextSelections: Record<string, string> = {};
  const visibleGroups: VariantGroup[] = [];
  let candidateProducts = [...productData];

  for (const group of variantGroups) {
    // Check if any candidate product matching previous selections defines this group
    const hasGroup = candidateProducts.some((prod) => {
      const attrs = getSkuAttributes(prod);
      return Boolean(attrs[group.id]);
    });

    if (!hasGroup) {
      // Group not applicable for current candidate products; skip it
      continue;
    }

    visibleGroups.push(group);

    // Available attribute item IDs for this group among current candidate products
    const availableItemIds = Array.from(
      new Set(
        candidateProducts
          .map((prod) => getSkuAttributes(prod)[group.id])
          .filter(Boolean)
      )
    );

    // Determine selected item ID for this group:
    // 1. Keep desired selection if valid
    // 2. Otherwise default to first available item
    const desiredVal = desiredSelections[group.id];
    let selectedVal = "";

    if (desiredVal && availableItemIds.includes(desiredVal)) {
      selectedVal = desiredVal;
    } else if (availableItemIds.length > 0) {
      selectedVal = availableItemIds[0];
    }

    if (selectedVal) {
      nextSelections[group.id] = selectedVal;
      // Narrow candidate products for downstream groups
      candidateProducts = candidateProducts.filter((prod) => {
        const attrs = getSkuAttributes(prod);
        return attrs[group.id] === selectedVal;
      });
    }
  }

  return { selections: nextSelections, visibleVariantGroups: visibleGroups };
}

export function useProductSelection(
  productData: ProductOptionDataModel[] = [],
  variantGroups: VariantGroup[] = []
) {
  const [selections, setSelections] = useState<Record<string, string>>(() => {
    if (productData.length > 0 && variantGroups.length > 0) {
      const { selections: initial } = resolveSelections({}, variantGroups, productData);
      return initial;
    }
    return {};
  });

  const { deliveryTimeList, holidaysList } = useProductData();
  const { getEstimatedDate } = useEstimatedDate(deliveryTimeList, holidaysList);
  const store = useProductStore();

  // Sync initial / updated selections when productData or variantGroups changes
  useEffect(() => {
    if (productData.length > 0 && variantGroups.length > 0) {
      setSelections((prev) => {
        const { selections: resolved } = resolveSelections(prev, variantGroups, productData);
        const isSame =
          Object.keys(resolved).length === Object.keys(prev).length &&
          Object.keys(resolved).every((k) => resolved[k] === prev[k]);
        return isSame ? prev : resolved;
      });
    }
  }, [productData, variantGroups]);

  // 1. Compute visible variant groups based on current selections
  const visibleVariantGroups = useMemo(() => {
    const { visibleVariantGroups } = resolveSelections(selections, variantGroups, productData);
    return visibleVariantGroups;
  }, [selections, variantGroups, productData]);

  // 2. Cascading available items for each visible step based on selections in previous steps
  const availableItemsMap = useMemo(() => {
    const availability: Record<string, string[]> = {};

    visibleVariantGroups.forEach((group, index) => {
      const precedingGroups = visibleVariantGroups.slice(0, index);

      // Filter products that match all previous selections
      const matchingProducts = productData.filter((prod) => {
        const skuAttrs = getSkuAttributes(prod);
        return precedingGroups.every((prev) => skuAttrs[prev.id] === selections[prev.id]);
      });

      // Collect available item IDs for current group
      const availableIds = matchingProducts
        .map((prod) => getSkuAttributes(prod)[group.id])
        .filter(Boolean);

      availability[group.id] = Array.from(new Set(availableIds));
    });

    return availability;
  }, [visibleVariantGroups, productData, selections]);

  // 3. Current unlock step
  const unlockedIndex = useMemo(() => {
    const firstUnselected = visibleVariantGroups.findIndex((group) => !selections[group.id]);
    return firstUnselected === -1 ? Math.max(0, visibleVariantGroups.length - 1) : firstUnselected;
  }, [visibleVariantGroups, selections]);

  // 4. Match exact product SKU when all visible dropdowns are selected
  const isAllSelected =
    visibleVariantGroups.length === 0
      ? productData.length > 0
      : visibleVariantGroups.every((g) => Boolean(selections[g.id]));

  const matchedProduct = useMemo(() => {
    if (!isAllSelected) return null;
    if (visibleVariantGroups.length === 0) return productData[0] || null;

    return (
      productData.find((prod) => {
        const skuAttrs = getSkuAttributes(prod);
        return visibleVariantGroups.every((g) => skuAttrs[g.id] === selections[g.id]);
      }) || null
    );
  }, [productData, selections, isAllSelected, visibleVariantGroups]);

  // Default to first product so base prices and quantity tiers are immediately visible
  const activeProduct = matchedProduct || productData[0] || null;

  // 5. Calculate option extra surcharge
  const optionsExtraPrice = useMemo(() => {
    if (!matchedProduct) return 0;

    return (matchedProduct.options || []).reduce((sum, opt) => {
      const variantId = String(opt.variantItemId?.variantId?._id || "");
      const itemId = String(opt.variantItemId?.attributeItemId?._id || "");
      const isSelected = selections[variantId] === itemId;
      return sum + (isSelected ? Number(opt.extraPrice || 0) : 0);
    }, 0);
  }, [matchedProduct, selections]);

  // 6. Calculate live tier prices
  const computedQuantities = useMemo(() => {
    return (activeProduct?.quantityOptions || [])
      .filter((tier) => tier.status !== false)
      .map((tier) => {
        const calc = computeTierPrice(tier, optionsExtraPrice);
        return {
          _id: tier._id,
          quantity: calc.quantity,
          price: calc.totalPrice,
          markBasePrice: calc.unitPrice,
          percentage: calc.discountPercent,
          unitPrice: calc.unitPrice,
          totalPrice: calc.totalPrice,
          withoutpercentageprice: calc.baseUnitPrice,
        };
      });
  }, [activeProduct, optionsExtraPrice]);

  // 7. Selection change handler
  const handleSelectionChange = useCallback(
    (variantId: string, itemId: string, _index?: number) => {
      setSelections((prev) => {
        const desired = { ...prev, [variantId]: itemId };
        const { selections: next } = resolveSelections(desired, variantGroups, productData);
        return next;
      });
    },
    [variantGroups, productData]
  );

  const resetSelections = useCallback(() => {
    const { selections: initial } = resolveSelections({}, variantGroups, productData);
    setSelections(initial);
  }, [variantGroups, productData]);

  // 8. Store synchronization
  useEffect(() => {
    store.setFinalProductOption(selections);
    store.setProductQuantity(computedQuantities);
    store.setTurnaroundTimeOption(activeProduct?.turnaroundOptions || []);

    if (!activeProduct || computedQuantities.length === 0) return;

    const currentQty = Number(store.selectQuantityAndEstimatedDate.quantity);
    const tier = computedQuantities.find((q) => q.quantity === currentQty) || computedQuantities[0];
    if (!tier) return;

    const turnaroundRange = (activeProduct.turnaroundOptions || []).find(
      (el) => tier.quantity >= Number(el.min) && tier.quantity <= Number(el.max)
    );
    const firstTurnaround = turnaroundRange?.turnaroundTimes?.[0];

    const formattedDate = firstTurnaround
      ? new Date(getEstimatedDate(firstTurnaround)).toLocaleDateString("en-us", {
        weekday: "long",
        year: "numeric",
        month: "short",
        day: "numeric",
        timeZone: "UTC",
      })
      : "";

    store.setQuantityAndEstimatedDate({
      productId: activeProduct._id,
      quantity: tier.quantity.toString(),
      productOptionPrice: (tier.price ?? 0).toString(),
      percentage: tier.percentage?.toString() || "0",
      turnaroundTime: firstTurnaround?.name || "",
      estimateCompleteDate: formattedDate,
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [activeProduct?._id, computedQuantities, optionsExtraPrice, selections]);

  const isConfigured = Boolean(isAllSelected && matchedProduct);

  return {
    selections,
    visibleVariantGroups,
    availableItemsMap,
    unlockedIndex,
    activeProduct,
    matchedProduct,
    isConfigured,
    deliveryTimeList,
    holidaysList,
    handleSelectionChange,
    resetSelections,
    store,
  };
}
