import { priceFreshness } from "@/lib/utils";

type RecommendationProduct = {
  id: string;
  slug: string;
  name: string;
  metalType: string;
  weight: string;
  purity: string;
  karat?: string | null;
  productType: string;
  brandMint?: string | null;
  mintBrand?: string | null;
  customerPrice?: unknown;
  totalSalePrice?: unknown;
  manualPrice?: unknown;
  premiumPercent?: unknown;
  spreadPercent?: unknown;
  liquidityScore?: unknown;
  shippingSpeedScore?: unknown;
  recommendationNotes?: string | null;
  isIraEligible?: boolean | null;
  isFeatured?: boolean | null;
  stockStatus?: string | null;
  inventoryStatus?: string | null;
  stockQuantity?: number | null;
  priceLastUpdatedAt?: Date | null;
  lastPriceUpdatedAt?: Date | null;
};

type RecommendationResult = {
  score: number;
  reasons: string[];
};

function clamp(value: number, min: number, max: number) {
  return Math.min(max, Math.max(min, value));
}

function normalizeLowerBetter(value: number, maxValue: number) {
  return clamp((1 - value / maxValue) * 100, 0, 100);
}

function normalizeScore(value: number) {
  return clamp((value / 5) * 100, 0, 100);
}

function stockScore(product: RecommendationProduct) {
  const stock = product.stockStatus || product.inventoryStatus || "IN_STOCK";
  const quantity = Number(product.stockQuantity ?? 0);

  if (stock === "OUT_OF_STOCK") return 0;
  if (stock === "LOW_STOCK") return quantity > 0 ? 60 : 40;
  if (quantity <= 0) return 40;
  if (quantity < 5) return 80;
  return 100;
}

function freshnessScore(product: RecommendationProduct) {
  const date = product.priceLastUpdatedAt || product.lastPriceUpdatedAt;
  if (!date) return 50;
  const freshness = priceFreshness(date);
  if (freshness === "fresh") return 100;
  if (freshness === "recommended") return 70;
  return 35;
}

export function calculateRecommendationScore(product: RecommendationProduct) {
  const premium = normalizeLowerBetter(Number(product.premiumPercent ?? 0), 25);
  const spread = normalizeLowerBetter(Number(product.spreadPercent ?? 0), 20);
  const liquidity = normalizeScore(Number(product.liquidityScore ?? 3));
  const shipping = normalizeScore(Number(product.shippingSpeedScore ?? 3));
  const stock = stockScore(product);
  const ira = product.isIraEligible ? 100 : 0;
  const freshness = freshnessScore(product);

  const weighted = (
    stock * 0.3 +
    premium * 0.2 +
    spread * 0.15 +
    liquidity * 0.15 +
    shipping * 0.1 +
    ira * 0.05 +
    freshness * 0.05
  );

  return Math.round(clamp(weighted, 0, 100));
}

export function getRecommendationReasons(product: RecommendationProduct, score = calculateRecommendationScore(product)) {
  const reasons: string[] = [];
  const stock = product.stockStatus || product.inventoryStatus || "IN_STOCK";
  const premium = Number(product.premiumPercent ?? 0);
  const spread = Number(product.spreadPercent ?? 0);
  const liquidity = Number(product.liquidityScore ?? 3);
  const shipping = Number(product.shippingSpeedScore ?? 3);
  const freshness = product.priceLastUpdatedAt || product.lastPriceUpdatedAt ? priceFreshness(product.priceLastUpdatedAt || product.lastPriceUpdatedAt || new Date()) : "recommended";

  if (stock === "IN_STOCK") reasons.push("In stock");
  else if (stock === "LOW_STOCK") reasons.push("Limited stock available");

  if (premium <= 5) reasons.push("Low entered premium");
  if (spread <= 5) reasons.push("Low entered spread");
  if (liquidity >= 4) reasons.push("Strong liquidity score");
  if (shipping >= 4) reasons.push("Fast shipping score");
  if (product.isIraEligible) reasons.push("IRA eligible");
  if (freshness === "fresh") reasons.push("Recently updated pricing");
  if (product.recommendationNotes) reasons.push(product.recommendationNotes);

  if (!reasons.length && score >= 70) reasons.push("Balanced product score");
  if (!reasons.length) reasons.push("Available for storefront review");

  return reasons.slice(0, 4);
}

export function getBestRecommendation<T extends RecommendationProduct>(products: T[]) {
  const eligible = products.filter((product) => {
    const stock = product.stockStatus || product.inventoryStatus || "IN_STOCK";
    return stock !== "OUT_OF_STOCK";
  });

  if (!eligible.length) return null;

  return eligible
    .map((product) => ({
      product,
      score: calculateRecommendationScore(product),
      reasons: getRecommendationReasons(product)
    }))
    .sort((a, b) => b.score - a.score || Number(b.product.isFeatured) - Number(a.product.isFeatured))[0] ?? null;
}

export function getRecommendationLeaderboard<T extends RecommendationProduct>(products: T[]) {
  return products
    .filter((product) => {
      const stock = product.stockStatus || product.inventoryStatus || "IN_STOCK";
      return stock !== "OUT_OF_STOCK";
    })
    .map((product) => ({
      product,
      score: calculateRecommendationScore(product),
      reasons: getRecommendationReasons(product)
    }))
    .sort((a, b) => b.score - a.score || Number(b.product.isFeatured) - Number(a.product.isFeatured));
}

export type { RecommendationProduct, RecommendationResult };
