"use client";

import { Plus, Trash2, WandSparkles } from "lucide-react";
import { Button } from "@/components/ui/button";
import { CurrencyInput } from "@/components/ui/currency-input";
import { formatMoney } from "@/utils/formatters";
import { nomeDaMedida, vendidoPorMedida } from "@/lib/adicionais";
import { DEFAULT_PRICING_RULE, getPriceSuggestion, type PricingRule } from "@/domain/pricing/getPriceSuggestion";
import {
  validateAndNormalizePriceTiers,
  validatePriceTiersAgainstSaleLimits,
  type ProductPriceTier,
  type ProductSaleQuantityLimits,
} from "@/lib/price-tiers";

type CategoryWithPricing = {
  pricing_rule?: PricingRule;
};

interface ProductPriceTiersProps {
  tiers: ProductPriceTier[];
  onChange: (tiers: ProductPriceTier[]) => void;
  basePrice: number;
  costTotal: number;
  priceOnRequest: boolean;
  category?: CategoryWithPricing | null;
  saleQuantityLimits?: ProductSaleQuantityLimits | null;
  readOnly?: boolean;
  readOnlyHint?: string;
  /* A unidade de venda do produto: por m², as faixas são por área. */
  unitType?: string | null;
}

const EPSILON = 0.000001;

function normalizeRows(rows: ProductPriceTier[]) {
  return rows.map((row, index) => ({
    ...row,
    min_qty: Number.isFinite(Number(row.min_qty)) ? Number(row.min_qty) : 0,
    max_qty: row.max_qty === null || row.max_qty === undefined ? null : Number(row.max_qty),
    unit_price: Number.isFinite(Number(row.unit_price)) ? Number(row.unit_price) : 0,
    sort_order: index,
    active: row.active ?? true,
  }));
}

function toNumberOrNull(value: unknown) {
  const parsed = Number(value);
  if (!Number.isFinite(parsed)) return null;
  return parsed;
}

function extractTierIndex(error: string | null) {
  if (!error) return null;
  const match = error.match(/faixa\s+(\d+)/i);
  if (!match) return null;
  const parsed = Number.parseInt(match[1], 10);
  if (!Number.isFinite(parsed) || parsed <= 0) return null;
  return parsed - 1;
}

function buildTierRowIssues(
  rows: ProductPriceTier[],
  priceOnRequest: boolean,
  saleQuantityLimits?: ProductSaleQuantityLimits | null,
  validationError?: string | null,
  limitsError?: string | null
) {
  const rowIssues = new Map<number, Set<string>>();
  const globalIssues: string[] = [];

  const pushRowIssue = (index: number, message: string) => {
    const current = rowIssues.get(index) ?? new Set<string>();
    current.add(message);
    rowIssues.set(index, current);
  };

  const minLimit =
    saleQuantityLimits?.min_sale_qty_enabled && saleQuantityLimits.min_sale_qty != null
      ? toNumberOrNull(saleQuantityLimits.min_sale_qty)
      : null;
  const maxLimit =
    saleQuantityLimits?.max_sale_qty_enabled && saleQuantityLimits.max_sale_qty != null
      ? toNumberOrNull(saleQuantityLimits.max_sale_qty)
      : null;
  const allowedLimits =
    saleQuantityLimits?.allowed_sale_qty_enabled && Array.isArray(saleQuantityLimits.allowed_sale_quantities)
      ? Array.from(
          new Set(
            saleQuantityLimits.allowed_sale_quantities
              .map((value) => Number(value))
              .filter((value) => Number.isFinite(value) && value > 0)
              .map((value) => Number(value.toFixed(3)))
          )
        ).sort((a, b) => a - b)
      : [];

  rows.forEach((row, index) => {
    const minQty = toNumberOrNull(row.min_qty);
    const maxQty = row.max_qty === null ? null : toNumberOrNull(row.max_qty);
    const unitPrice = toNumberOrNull(row.unit_price);

    if (minQty === null || minQty <= 0) {
      pushRowIssue(index, "Quantidade mínima da faixa deve ser maior que zero.");
    }

    if (unitPrice === null || unitPrice <= 0) {
      pushRowIssue(index, "Preço unitário da faixa deve ser maior que zero.");
    }

    if (row.max_qty !== null) {
      if (maxQty === null || maxQty <= 0) {
        pushRowIssue(index, "Quantidade máxima da faixa deve ser maior que zero.");
      } else if (minQty !== null && maxQty + EPSILON < minQty) {
        pushRowIssue(index, "Quantidade máxima não pode ser menor que a mínima.");
      }
    }

    if (!priceOnRequest) {
      if (minLimit !== null && minQty !== null && minQty + EPSILON < minLimit) {
        pushRowIssue(index, `Início da faixa abaixo da quantidade mínima de venda (${minLimit}).`);
      }
      if (maxLimit !== null && minQty !== null && minQty - EPSILON > maxLimit) {
        pushRowIssue(index, `Início da faixa acima da quantidade máxima de venda (${maxLimit}).`);
      }
      if (maxLimit !== null && maxQty !== null && maxQty - EPSILON > maxLimit) {
        pushRowIssue(index, `Fim da faixa acima da quantidade máxima de venda (${maxLimit}).`);
      }
      if (allowedLimits.length > 0 && minQty !== null) {
        const minAllowed = allowedLimits.some((value) => Math.abs(value - minQty) <= EPSILON);
        if (!minAllowed) {
          pushRowIssue(index, `Início da faixa não está nas quantidades permitidas (${minQty}).`);
        }
      }
      if (allowedLimits.length > 0 && maxQty === null) {
        pushRowIssue(index, "Com Intervalo de Quantidades, o máximo deve ser igual ao mínimo.");
      }
      if (allowedLimits.length > 0 && maxQty !== null && minQty !== null && Math.abs(maxQty - minQty) > EPSILON) {
        pushRowIssue(index, "Com Intervalo de Quantidades, use faixa exata (mínimo = máximo).");
      }
      if (allowedLimits.length > 0 && maxQty !== null) {
        const maxAllowed = allowedLimits.some((value) => Math.abs(value - maxQty) <= EPSILON);
        if (!maxAllowed) {
          pushRowIssue(index, `Fim da faixa não está nas quantidades permitidas (${maxQty}).`);
        }
      }
    }
  });

  if (allowedLimits.length > 0) {
    const covered = new Set<number>();
    rows.forEach((row) => {
      const minQty = toNumberOrNull(row.min_qty);
      const maxQty = row.max_qty === null ? null : toNumberOrNull(row.max_qty);
      if (minQty === null || maxQty === null) return;
      if (Math.abs(minQty - maxQty) > EPSILON) return;
      const matched = allowedLimits.find((value) => Math.abs(value - minQty) <= EPSILON);
      if (matched !== undefined) covered.add(matched);
    });
    const missing = allowedLimits.filter((value) => !covered.has(value));
    if (missing.length > 0) {
      globalIssues.push(
        `Faltam faixas exatas para: ${missing
          .map((value) => String(Number(value.toFixed(3))))
          .join(", ")}.`
      );
    }
  }

  for (let index = 1; index < rows.length; index += 1) {
    const previous = rows[index - 1];
    const current = rows[index];
    const previousMax = previous.max_qty === null ? Number.POSITIVE_INFINITY : toNumberOrNull(previous.max_qty);
    const currentMin = toNumberOrNull(current.min_qty);
    if (previousMax === null || currentMin === null) continue;
    if (currentMin <= previousMax + EPSILON) {
      pushRowIssue(index, "Faixa sobrepõe a faixa anterior. Ajuste os intervalos.");
    }
  }

  if (validationError) {
    const validationIndex = extractTierIndex(validationError);
    if (validationIndex !== null) {
      pushRowIssue(validationIndex, validationError);
    } else {
      globalIssues.push(validationError);
    }
  }

  if (limitsError) {
    const limitsIndex = extractTierIndex(limitsError);
    if (limitsIndex !== null) {
      pushRowIssue(limitsIndex, limitsError);
    } else {
      globalIssues.push(limitsError);
    }
  }

  return { rowIssues, globalIssues };
}

export function ProductPriceTiers({
  tiers,
  onChange,
  basePrice,
  costTotal,
  priceOnRequest,
  category,
  saleQuantityLimits,
  readOnly = false,
  readOnlyHint,
  unitType = "unit",
}: ProductPriceTiersProps) {
  const controlsDisabled = priceOnRequest || readOnly;
  /* Produto por m²: as faixas falam de área, e o texto precisa dizer isso. */
  const porMedida = vendidoPorMedida(unitType);
  const medida = nomeDaMedida(unitType);
  const normalizedRows = normalizeRows(tiers);
  const validation = validateAndNormalizePriceTiers(normalizedRows);
  const limitsValidation = validatePriceTiersAgainstSaleLimits(
    normalizedRows,
    priceOnRequest ? null : saleQuantityLimits
  );
  const tierIssues = buildTierRowIssues(
    normalizedRows,
    priceOnRequest,
    saleQuantityLimits,
    validation.error,
    limitsValidation.error
  );

  const categoryRule = category?.pricing_rule ?? DEFAULT_PRICING_RULE;
  const canSuggest = (categoryRule.qtyTiers?.length || 0) > 0 && costTotal > 0;

  function updateRows(nextRows: ProductPriceTier[]) {
    onChange(normalizeRows(nextRows));
  }

  function addTier() {
    const last = normalizedRows[normalizedRows.length - 1];
    const nextMin = last ? Number(((last.max_qty ?? last.min_qty) + 1).toFixed(3)) : 1;
    updateRows([
      ...normalizedRows,
      {
        min_qty: nextMin > 0 ? nextMin : 1,
        max_qty: null,
        unit_price: Number(basePrice) || 0,
        sort_order: normalizedRows.length,
        active: true,
      },
    ]);
  }

  function removeTier(index: number) {
    updateRows(normalizedRows.filter((_, rowIndex) => rowIndex !== index));
  }

  function updateTier(index: number, patch: Partial<ProductPriceTier>) {
    updateRows(normalizedRows.map((row, rowIndex) => (rowIndex === index ? { ...row, ...patch } : row)));
  }

  function generateFromCategoryRule() {
    if (!canSuggest) return;
    const tierRules = [...(categoryRule.qtyTiers || [])].sort((a, b) => a.minQty - b.minQty);
    const generated = tierRules.map((tier, index) => ({
      min_qty: Number(tier.minQty.toFixed(3)),
      max_qty: tier.maxQty === undefined ? null : Number(tier.maxQty.toFixed(3)),
      unit_price: getPriceSuggestion(costTotal, tier.minQty, categoryRule).suggestedPrice,
      sort_order: index,
      active: true,
    }));
    updateRows(generated);
  }

  return (
    <div className="ks-surface p-6 space-y-4">
      <div className="flex flex-wrap items-start justify-between gap-3">
        <div>
          <h3 className="text-base font-semibold text-[var(--ks-color-text-primary)]">
            {porMedida ? `Faixas por ${unitType === "square_meter" ? "área" : "metragem"} (${medida})` : "Preço por quantidade"}
          </h3>
          <p className="text-sm text-[var(--ks-color-text-muted)]">
            {porMedida
              ? `A faixa é escolhida pela ${unitType === "square_meter" ? "área" : "metragem"} total do pedido (peças × medida), não pelo número de peças. Exemplo: 2 peças de 1 × 1 m são 2 ${medida}, e vale a faixa que inclui 2 ${medida}.`
              : "Configure faixas para reduzir o preço unitário conforme a quantidade."}
          </p>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <Button type="button" variant="ghost" onClick={addTier} disabled={controlsDisabled} icon={<Plus size={14} />}>
            Nova faixa
          </Button>
          {canSuggest && (
            <Button type="button" variant="secondary" onClick={generateFromCategoryRule} disabled={controlsDisabled} icon={<WandSparkles size={14} />}>
              Sugerir pelas regras
            </Button>
          )}
        </div>
      </div>

      {readOnly && (
        <div className="rounded-xl border border-blue-200 bg-blue-50 px-4 py-3 text-sm text-blue-700">
          {readOnlyHint || "As faixas estão bloqueadas para edição neste modo."}
        </div>
      )}

      {priceOnRequest && (
        <div className="rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-700">
          Preço sob consulta ativo. As faixas de quantidade não serão aplicadas.
        </div>
      )}

      {normalizedRows.length === 0 ? (
        <div className="rounded-xl border border-dashed border-[var(--ks-color-border-subtle)] px-4 py-6 text-sm text-[var(--ks-color-text-soft)]">
          Nenhuma faixa cadastrada. O sistema usará o preço base ({formatMoney(basePrice || 0)}) em qualquer quantidade.
        </div>
      ) : (
        <div className="space-y-3">
          {normalizedRows.map((tier, index) => {
            const issues = Array.from(tierIssues.rowIssues.get(index) ?? []);
            const hasIssue = issues.length > 0;

            return (
              <div
                key={index}
                className={`space-y-2 rounded-2xl border bg-white p-4 ${
                  hasIssue
                    ? "border-amber-300 shadow-[0_0_0_1px_rgba(245,158,11,0.25)]"
                    : "border-[var(--ks-color-border-subtle)]"
                }`}
              >
                <div className="flex items-center justify-between">
                  <span className="text-[11px] font-semibold uppercase tracking-[0.14em] text-[var(--ks-color-text-soft)]">
                    Faixa {index + 1}
                  </span>
                  {hasIssue && (
                    <span className="rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-amber-700">
                      Ajuste necessário
                    </span>
                  )}
                </div>

                <div className="grid grid-cols-1 gap-3 md:grid-cols-[1fr_1fr_1fr_auto]">
                  <div className="space-y-1">
                    <label className="text-xs font-medium uppercase tracking-[0.16em] text-[var(--ks-color-text-soft)]">
                      {porMedida ? `A partir de (${medida})` : "Qtd. mínima"}
                    </label>
                    <input
                      type="number"
                      min={0}
                      step="0.001"
                      value={tier.min_qty}
                      disabled={controlsDisabled}
                      onChange={(event) => updateTier(index, { min_qty: Number(event.target.value) || 0 })}
                      className="w-full rounded-full border border-[rgba(198,203,224,0.9)] bg-white px-4 py-2 text-sm outline-none transition-all focus:border-[rgba(10,192,214,0.9)] focus:ring-2 focus:ring-[rgba(10,192,214,0.16)] disabled:bg-[rgba(248,249,252,0.9)]"
                    />
                  </div>

                  <div className="space-y-1">
                    <label className="text-xs font-medium uppercase tracking-[0.16em] text-[var(--ks-color-text-soft)]">
                      {porMedida ? `Até (${medida}, opcional)` : "Qtd. máxima (opcional)"}
                    </label>
                    <input
                      type="number"
                      min={0}
                      step="0.001"
                      value={tier.max_qty ?? ""}
                      disabled={controlsDisabled}
                      onChange={(event) => {
                        const raw = event.target.value.trim();
                        updateTier(index, { max_qty: raw ? Number(raw) || 0 : null });
                      }}
                      className="w-full rounded-full border border-[rgba(198,203,224,0.9)] bg-white px-4 py-2 text-sm outline-none transition-all focus:border-[rgba(10,192,214,0.9)] focus:ring-2 focus:ring-[rgba(10,192,214,0.16)] disabled:bg-[rgba(248,249,252,0.9)]"
                    />
                  </div>

                  <div className="space-y-1">
                    <label className="text-xs font-medium uppercase tracking-[0.16em] text-[var(--ks-color-text-soft)]">
                      {porMedida ? `Preço do ${medida}` : "Preço unitário"}
                    </label>
                    <CurrencyInput
                      value={tier.unit_price}
                      disabled={controlsDisabled}
                      onChange={(value) => updateTier(index, { unit_price: value })}
                      className="rounded-full"
                    />
                  </div>

                  <div className="flex items-end justify-end">
                    <button
                      type="button"
                      onClick={() => removeTier(index)}
                      disabled={controlsDisabled}
                      className="inline-flex h-10 w-10 items-center justify-center rounded-xl border border-[var(--ks-color-border-subtle)] text-[var(--ks-color-text-soft)] transition-colors hover:border-rose-200 hover:bg-rose-50 hover:text-rose-600 disabled:cursor-not-allowed disabled:opacity-50"
                      aria-label="Remover faixa"
                    >
                      <Trash2 size={16} />
                    </button>
                  </div>
                </div>

                {hasIssue && (
                  <div className="rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800">
                    {issues.map((issue) => (
                      <div key={`${index}-${issue}`}>{issue}</div>
                    ))}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      )}

      <div className="rounded-xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-surface-secondary)] px-4 py-3 text-xs text-[var(--ks-color-text-muted)]">
        <div>Preço base, quando nenhuma faixa vale: {formatMoney(basePrice || 0)}</div>
        <div>Deixe a quantidade máxima em branco para uma faixa sem limite.</div>
      </div>

      {tierIssues.globalIssues.map((message) => (
        <div
          key={message}
          className="rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-700"
        >
          {message}
        </div>
      ))}
    </div>
  );
}
