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

export type TierValidationResult = {
  tiers: ProductPriceTier[];
  error: string | null;
};

export type TierSaleLimitsValidationResult = {
  error: string | null;
};

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 parseNumericInput(value: unknown): number {
  if (typeof value === "number") return Number.isFinite(value) ? value : NaN;
  if (typeof value !== "string") return NaN;

  const raw = value.trim();
  if (!raw) return NaN;

  const hasComma = raw.includes(",");
  const hasDot = raw.includes(".");

  if (hasComma && hasDot) {
    return Number.parseFloat(raw.replace(/\./g, "").replace(",", "."));
  }

  return Number.parseFloat(raw.replace(",", "."));
}

function parsePositiveInput(value: unknown): number | null {
  const parsed = parseNumericInput(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 width = Number(item.width_m) || 0;
  const height = Number(item.height_m) || 0;
  const length = Number(item.length_m) || 0;
  const unitType = item.unit_type || "unit";

  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 validatePriceTiersAgainstSaleLimits(
  tiers: ProductPriceTier[] | null | undefined,
  limits: ProductSaleQuantityLimits | null | undefined
): TierSaleLimitsValidationResult {
  if (!Array.isArray(tiers) || tiers.length === 0) return { error: null };

  const sorted = sortProductPriceTiers(
    tiers.map((tier, index) => ({
      ...tier,
      sort_order: tier.sort_order ?? index,
      active: tier.active ?? true,
    }))
  );
  const { minQty, maxQty, allowedQuantities } = resolveSaleQuantityLimits(limits);

  for (let index = 0; index < sorted.length; index += 1) {
    const tier = sorted[index];
    const tierMin = Number(tier.min_qty);
    const tierMax = tier.max_qty === null ? null : Number(tier.max_qty);

    if (minQty !== null && tierMin + EPSILON < minQty) {
      return {
        error: `A faixa ${index + 1} inicia em ${tierMin}, abaixo da quantidade mínima de venda (${minQty}).`,
      };
    }

    if (maxQty !== null) {
      if (tierMin - EPSILON > maxQty) {
        return {
          error: `A faixa ${index + 1} inicia em ${tierMin}, acima da quantidade máxima de venda (${maxQty}).`,
        };
      }
      if (tierMax !== null && tierMax - EPSILON > maxQty) {
        return {
          error: `A faixa ${index + 1} termina em ${tierMax}, acima da quantidade máxima de venda (${maxQty}).`,
        };
      }
    }

    if (allowedQuantities.length > 0) {
      const tierMinAllowed = allowedQuantities.some((value) => Math.abs(value - tierMin) <= EPSILON);
      if (!tierMinAllowed) {
        return {
          error: `A faixa ${index + 1} inicia em ${tierMin}, que não está nas quantidades permitidas.`,
        };
      }

      if (tierMax === null) {
        return {
          error: `A faixa ${index + 1} precisa ter máximo igual ao mínimo quando Intervalo de Quantidades estiver ativo.`,
        };
      }

      if (Math.abs(tierMax - tierMin) > EPSILON) {
        return {
          error: `A faixa ${index + 1} deve ser exata (mínimo = máximo) para usar Intervalo de Quantidades.`,
        };
      }

      const tierMaxAllowed = allowedQuantities.some((value) => Math.abs(value - tierMax) <= EPSILON);
      if (!tierMaxAllowed) {
        return {
          error: `A faixa ${index + 1} termina em ${tierMax}, que não está nas quantidades permitidas.`,
        };
      }
    }
  }

  if (allowedQuantities.length > 0) {
    const covered = new Set<number>();
    for (const tier of sorted) {
      const tierMin = Number(tier.min_qty);
      const tierMax = tier.max_qty === null ? null : Number(tier.max_qty);
      if (!Number.isFinite(tierMin) || tierMax === null || !Number.isFinite(tierMax)) continue;
      if (Math.abs(tierMin - tierMax) > EPSILON) continue;
      const matched = allowedQuantities.find((value) => Math.abs(value - tierMin) <= EPSILON);
      if (matched !== undefined) covered.add(matched);
    }

    const missing = allowedQuantities.filter((value) => !covered.has(value));
    if (missing.length > 0) {
      return {
        error: `Faltam faixas para as quantidades permitidas: ${missing
          .map((value) => String(Number(value.toFixed(3))))
          .join(", ")}.`,
      };
    }
  }

  return { error: null };
}

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 sortProductPriceTiers<T extends ProductPriceTier>(tiers: T[]): T[] {
  return [...tiers].sort((a, b) => {
    const minDiff = a.min_qty - b.min_qty;
    if (Math.abs(minDiff) > EPSILON) return minDiff;

    const aMax = a.max_qty === null ? Number.POSITIVE_INFINITY : a.max_qty;
    const bMax = b.max_qty === null ? Number.POSITIVE_INFINITY : b.max_qty;
    return aMax - bMax;
  });
}

export function validateAndNormalizePriceTiers(raw: unknown): TierValidationResult {
  if (raw === undefined || raw === null) return { tiers: [], error: null };
  if (!Array.isArray(raw)) return { tiers: [], error: "Formato inválido para faixas de preço." };

  const parsed: ProductPriceTier[] = [];

  for (let index = 0; index < raw.length; index += 1) {
    const row = raw[index];
    if (!row || typeof row !== "object" || Array.isArray(row)) {
      return { tiers: [], error: `Faixa ${index + 1} inválida.` };
    }

    const record = row as Record<string, unknown>;
    const minQty = parseNumericInput(record.min_qty);
    const unitPrice = parseNumericInput(record.unit_price);
    const maxRaw = record.max_qty;
    const maxQtyParsed =
      maxRaw === null || maxRaw === undefined || maxRaw === ""
        ? null
        : parseNumericInput(maxRaw);
    const active = record.active === undefined ? true : Boolean(record.active);

    if (!Number.isFinite(minQty) || minQty <= 0) {
      return { tiers: [], error: `A faixa ${index + 1} precisa ter quantidade mínima maior que zero.` };
    }

    if (!Number.isFinite(unitPrice) || unitPrice <= 0) {
      return { tiers: [], error: `A faixa ${index + 1} precisa ter preço unitário maior que zero.` };
    }

    if (maxQtyParsed !== null) {
      if (!Number.isFinite(maxQtyParsed) || maxQtyParsed <= 0) {
        return { tiers: [], error: `A faixa ${index + 1} possui quantidade máxima inválida.` };
      }
      if (maxQtyParsed + EPSILON < minQty) {
        return { tiers: [], error: `A faixa ${index + 1} possui máximo menor que o mínimo.` };
      }
    }

    parsed.push({
      min_qty: Number(minQty.toFixed(3)),
      max_qty: maxQtyParsed === null ? null : Number(maxQtyParsed.toFixed(3)),
      unit_price: Number(unitPrice.toFixed(2)),
      sort_order: index,
      active,
    });
  }

  const sorted = sortProductPriceTiers(parsed).map((tier, index) => ({
    ...tier,
    sort_order: index,
  }));

  for (let index = 1; index < sorted.length; index += 1) {
    const previous = sorted[index - 1];
    const current = sorted[index];
    const previousMax = previous.max_qty === null ? Number.POSITIVE_INFINITY : previous.max_qty;

    if (current.min_qty <= previousMax + EPSILON) {
      return {
        tiers: [],
        error: "As faixas de quantidade se sobrepõem. Ajuste os intervalos para não cruzarem.",
      };
    }
  }

  return { tiers: sorted, error: null };
}

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

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

  const matching = normalizedTiers
    .filter((tier) => {
      if (quantity + EPSILON < tier.min_qty) return false;
      if (tier.max_qty !== null && quantity - EPSILON > tier.max_qty) return false;
      return true;
    })
    .sort((a, b) => b.min_qty - a.min_qty);

  const tier = matching[0] || null;
  if (!tier) return { unitPrice: normalizedBase, tier: null as ProductPriceTier | null };
  return { unitPrice: Number(tier.unit_price) || 0, tier };
}
