export type ProductPriceTier = {
  min_qty: number;
  max_qty: number | null;
  unit_price: number;
  sort_order?: number | null;
  active?: boolean | null;
};

export type TierDiscountOffer = {
  tier: ProductPriceTier;
  discountPct: number;
};

export type ProductSaleQuantityLimits = {
  min_sale_qty_enabled?: boolean | null;
  min_sale_qty?: number | null;
  max_sale_qty_enabled?: boolean | null;
  max_sale_qty?: number | null;
  allowed_sale_qty_enabled?: boolean | null;
  allowed_sale_quantities?: number[] | null;
};

export type SaleQuantityCheckResult = {
  minQty: number | null;
  maxQty: number | null;
  allowedQuantities: number[];
  effectiveQuantity: number;
  isBelowMin: boolean;
  isAboveMax: boolean;
  isNotAllowedValue: boolean;
  isValid: boolean;
};

type EffectiveQuantityInput = {
  quantity: number;
  unit_type?: string | null;
  width_m?: number | null;
  height_m?: number | null;
  length_m?: number | null;
};

const EPSILON = 0.000001;

function parsePositiveInput(value: unknown): number | null {
  const parsed = Number(value);
  if (!Number.isFinite(parsed) || parsed <= 0) return null;
  return parsed;
}

function normalizeQuantityValue(value: number) {
  return Number(value.toFixed(3));
}

function parseAllowedSaleQuantitiesInput(value: unknown): number[] {
  const rawValues: number[] = [];

  if (Array.isArray(value)) {
    for (const entry of value) {
      const parsed = parsePositiveInput(entry);
      if (parsed !== null) rawValues.push(normalizeQuantityValue(parsed));
    }
  } else if (typeof value === "string") {
    const chunks = value
      .split(/[\s,;|/]+/)
      .map((chunk) => chunk.trim())
      .filter(Boolean);
    for (const chunk of chunks) {
      const parsed = parsePositiveInput(chunk);
      if (parsed !== null) rawValues.push(normalizeQuantityValue(parsed));
    }
  }

  if (rawValues.length === 0) return [];
  return Array.from(new Set(rawValues)).sort((a, b) => a - b);
}

export function calculateEffectiveQuantity(item: EffectiveQuantityInput): number {
  const quantity = Number(item.quantity) || 0;
  if (quantity <= 0) return 0;

  const unitType = item.unit_type || "unit";
  const width = Number(item.width_m) || 0;
  const height = Number(item.height_m) || 0;
  const length = Number(item.length_m) || 0;

  if (unitType === "square_meter") {
    const area = width * height;
    return area > 0 ? quantity * area : quantity;
  }

  if (unitType === "linear_meter" || unitType === "meter") {
    return length > 0 ? quantity * length : quantity;
  }

  return quantity;
}

export function resolveSaleQuantityLimits(input: ProductSaleQuantityLimits | null | undefined) {
  const minEnabled = Boolean(input?.min_sale_qty_enabled);
  const maxEnabled = Boolean(input?.max_sale_qty_enabled);
  const allowedEnabled = Boolean(input?.allowed_sale_qty_enabled);

  const minQty = minEnabled ? parsePositiveInput(input?.min_sale_qty) : null;
  const maxQty = maxEnabled ? parsePositiveInput(input?.max_sale_qty) : null;
  const allowedQuantities = allowedEnabled ? parseAllowedSaleQuantitiesInput(input?.allowed_sale_quantities) : [];

  return { minQty, maxQty, allowedQuantities };
}

export function checkSaleQuantityLimits(
  input: ProductSaleQuantityLimits & {
    effectiveQuantity: number;
  }
): SaleQuantityCheckResult {
  const { minQty, maxQty, allowedQuantities } = resolveSaleQuantityLimits(input);
  const effectiveQuantity = Number.isFinite(input.effectiveQuantity) ? input.effectiveQuantity : 0;

  const isBelowMin = minQty !== null && effectiveQuantity + EPSILON < minQty;
  const isAboveMax = maxQty !== null && effectiveQuantity - EPSILON > maxQty;
  const isNotAllowedValue =
    allowedQuantities.length > 0 &&
    !allowedQuantities.some((value) => Math.abs(value - effectiveQuantity) <= EPSILON);

  return {
    minQty,
    maxQty,
    allowedQuantities,
    effectiveQuantity,
    isBelowMin,
    isAboveMax,
    isNotAllowedValue,
    isValid: !isBelowMin && !isAboveMax && !isNotAllowedValue,
  };
}

export function resolveTierPrice(
  basePrice: number,
  effectiveQuantity: number,
  tiers: ProductPriceTier[] | null | undefined
) {
  const safeBase = Number(basePrice) || 0;
  const safeQuantity = Number(effectiveQuantity) || 0;
  const normalizedTiers = Array.isArray(tiers) ? tiers.filter((tier) => tier.active !== false) : [];

  if (safeQuantity <= 0 || normalizedTiers.length === 0) {
    return { unitPrice: safeBase, tier: null as ProductPriceTier | null };
  }

  const matched = normalizedTiers
    .filter((tier) => {
      if (safeQuantity + EPSILON < tier.min_qty) return false;
      if (tier.max_qty !== null && safeQuantity - EPSILON > tier.max_qty) return false;
      return true;
    })
    .sort((a, b) => (Number(b.min_qty) || 0) - (Number(a.min_qty) || 0))[0] || null;

  if (!matched) return { unitPrice: safeBase, tier: null as ProductPriceTier | null };
  return { unitPrice: Number(matched.unit_price) || 0, tier: matched };
}

export function calculateTierDiscountPct(basePrice: number, tierUnitPrice: number) {
  const safeBase = Number(basePrice) || 0;
  const safeTierPrice = Number(tierUnitPrice) || 0;
  if (safeBase <= 0 || safeTierPrice <= 0 || safeTierPrice >= safeBase) return 0;
  return ((safeBase - safeTierPrice) / safeBase) * 100;
}

export function getBestTierDiscount(
  basePrice: number,
  tiers: ProductPriceTier[] | null | undefined
): TierDiscountOffer | null {
  const safeBase = Number(basePrice) || 0;
  if (safeBase <= 0 || !Array.isArray(tiers) || tiers.length === 0) return null;

  const activeTiers = tiers.filter((tier) => tier.active !== false);
  let best: TierDiscountOffer | null = null;

  for (const tier of activeTiers) {
    const discountPct = calculateTierDiscountPct(safeBase, tier.unit_price);
    if (discountPct <= 0) continue;

    if (!best) {
      best = { tier, discountPct };
      continue;
    }

    const isBiggerDiscount = discountPct - best.discountPct > EPSILON;
    const isSameDiscount = Math.abs(discountPct - best.discountPct) <= EPSILON;
    const startsEarlier = Number(tier.min_qty) < Number(best.tier.min_qty);

    if (isBiggerDiscount || (isSameDiscount && startsEarlier)) {
      best = { tier, discountPct };
    }
  }

  return best;
}
