"use client";

import { usePermissoes } from "@/lib/permissoes-do-usuario";
import {
  CamposFiscaisDoProduto,
  DADOS_FISCAIS_VAZIOS,
  lerDadosFiscaisDoProduto,
  patchFiscalDoProduto,
  problemaNosDadosFiscais,
  type DadosFiscaisDoProduto,
} from "@/components/fiscal/campos-fiscais-do-produto";
import Image from "next/image";
import { useState, useEffect, useCallback, useMemo, useRef } from "react";
import { getSupabaseClient } from "@/lib/supabase";
import { getCompanyContext } from "@/lib/company-context";
import { custoBaseDaComposicao } from "@/lib/estoque/regras";
import { useEstoqueV2 } from "@/lib/estoque/use-estoque-v2";
import { CampoDecimal } from "@/components/ui/campo-decimal";
import { EstoqueDoProduto } from "@/components/estoque/estoque-do-produto";
import { ArrowLeft, Save, Loader2, Info, DollarSign, Package, History, Boxes, Plus, Trash2, ChevronDown, Dices, Pencil, Check, Calculator, Layers, BadgeDollarSign, Settings2, Blocks, Images, Store, Clock3, FileText, ExternalLink, Link2, Truck, Ruler, Weight, Clapperboard } from "lucide-react";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { CustomSelect } from "@/components/ui/custom-select";
import { PageHeader } from "@/components/ui/page-header";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { Aviso } from "@/components/ui/aviso";
import { RichTextEditor } from "@/components/ui/rich-text-editor";
import { formatMoney, formatMoneyInput, parseMoneyInput } from "@/utils/formatters";
import { nomeDaMedida, vendidoPorMedida } from "@/lib/adicionais";
import { descriptionToEditorHtml } from "@/lib/product-description-rich-text";
import { getPrimaryProductImageUrl, ProductImageItem } from "@/lib/product-images";

import { InfoTooltip } from "@/components/ui/info-tooltip";
import { PricingRule, DEFAULT_PRICING_RULE } from "@/domain/pricing/getPriceSuggestion";
import { calcularPreco } from "@/lib/precificacao/motor";
import { custoDoProduto } from "@/lib/precificacao/custo-do-produto";
import { medidaDaBase, type BaseDeConsumo } from "@/lib/precificacao/composicao";
// UI Components
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ProductComposition } from "@/components/pricing/product-composition";
import { ProductVariations, ProductAttribute, ProductOption, ProductVariation } from "@/components/products/product-variations";
import { ProductOptionalServices } from "@/components/products/product-optional-services";
import { lerCusto, lerGrupos, lerServicos, type CustoDoServico, type GrupoDeServicos, type ServicoOpcional } from "@/lib/servicos-opcionais";
import { lerVinculosDeServico, type VinculoDeServico } from "@/lib/vinculos-de-servico";
import { InventoryHistoryModal } from "@/components/products/inventory-history-modal";
import { ProductPriceTiers } from "@/components/products/product-price-tiers";
import { ProductImageGalleryEditor } from "@/components/products/product-image-gallery-editor";
import { VIDEO_VAZIO, VideoDoProdutoEditor, videoDoProdutoSalvo, videoParaSalvar, type VideoDoProdutoNoCadastro } from "@/components/products/video-do-produto-editor";
import { ProductProductionFileUpload } from "@/components/products/product-production-file-upload";
import { CategoryFormModal } from "@/components/categories/category-form-modal";
import { BarcodeGenerator } from "@/components/products/barcode-generator";
import { ProductCombos } from "@/components/products/product-combos";
import { ProductCustomFields } from "@/components/products/product-custom-fields";
import { ProductPriceTier, validatePriceTiersAgainstSaleLimits } from "@/lib/price-tiers";
import {
  normalizeProductCustomFieldsConfig,
  ProductCustomFieldConfig,
} from "@/lib/product-custom-fields";
import {
  buildAllowedQuantityPricing,
  createQuantityIntervalDraft,
  hydrateQuantityIntervalsFromProduct,
  parseQuantityIntervalsDrafts,
  type QuantityIntervalDraft,
} from "@/lib/quantity-intervals";


interface Category {
  id: string;
  name: string;
  pricing_rule?: PricingRule;
}

type ProductionTemplateFormat = "pdf" | "ai" | "cdr" | "canva";
type ProductionTemplateFormItem = {
  format: ProductionTemplateFormat;
  url: string;
  name: string;
};

function formatProductionLeadTime(value: number | null, unit: "hours" | "days" | "business_days" | "weeks" | null) {
  if (!Number.isFinite(value) || value === null || value <= 0 || !unit) return "";
  const normalizedValue = Number(value);
  const displayValue = Number.isInteger(normalizedValue)
    ? String(normalizedValue)
    : normalizedValue.toFixed(2).replace(/\.?0+$/, "");
  const singular = normalizedValue === 1;

  const label =
    unit === "hours"
      ? singular
        ? "hora"
        : "horas"
      : unit === "days"
        ? singular
          ? "dia corrido"
          : "dias corridos"
        : unit === "weeks"
          ? singular
            ? "semana"
            : "semanas"
          : singular
            ? "dia útil"
            : "dias úteis";

  return `${displayValue} ${label}`;
}

function PricingBlock({
  costTotal,
  price,
  onApplyPrice,
  category,
  variaveisPct,
  custoFixoUnitario,
  unidadeDeVenda,
}: {
  costTotal: number,
  price: number,
  onApplyPrice: (val: number) => void,
  category?: Category,
  variaveisPct: number,
  /* Custos fixos absorvidos pelo tempo da ficha, em R$ por unidade de venda:
     minutos da ficha × hora da estrutura. Zero quando a empresa não
     configurou as horas produtivas — ou o produto não tem ficha de tempo. */
  custoFixoUnitario: number,
  unidadeDeVenda: string,
}) {
  const [qty, setQty] = useState(1);
  /* O mesmo motor da tela de precificação: os custos variáveis da venda
     (imposto, taxa, perda) entram no divisor, junto com a margem da categoria.
     Antes esta análise usava a álgebra antiga (custo ÷ (1 − margem)) e
     contradizia o assistente — duas respostas para a mesma pergunta. */
  const rule = category?.pricing_rule || DEFAULT_PRICING_RULE;
  const resultado = calcularPreco({
    custoUnitario: costTotal,
    quantidade: qty,
    modo: "unidade",
    regra: rule,
    custosVariaveisPct: variaveisPct,
    custoFixoUnitario,
  });
  const suggestion = {
    suggestedPrice: resultado.precoUnitario,
    warnings: resultado.avisos,
  };

  /* Margem de contribuição de verdade: o que sobra depois do custo, dos
     fixos pelo tempo E dos variáveis — é a margem que o assistente promete. */
  const variaveisValor = (price * variaveisPct) / 100;
  const currentMargin = price > 0 ? ((price - costTotal - custoFixoUnitario - variaveisValor) / price) * 100 : 0;
  const isMarginLow = currentMargin < (category?.pricing_rule?.marginMinPct || DEFAULT_PRICING_RULE.marginMinPct);
  const isPriceBelowCost = price < costTotal + custoFixoUnitario + variaveisValor && price > 0;

  return (
    <div className="ks-surface p-4 border border-[var(--ks-color-border-subtle)] rounded-xl space-y-4 bg-slate-50/50">
      <div className="flex items-center justify-between">
        <h4 className="font-semibold text-sm uppercase tracking-wide text-slate-500 flex items-center gap-2">
          Análise de Precificação
          <InfoTooltip text="Sugestão baseada nas regras da categoria e custo total." />
        </h4>
        <div className="flex items-center gap-2 text-xs">
          <span className="text-slate-400">Quantidade simulada:</span>
          <CampoDecimal
            valor={qty}
            aoMudar={(n) => setQty(Math.max(1, Math.round(n) || 1))}
            casas={0}
            aria-label="Quantidade simulada"
            className="w-12 px-1 py-0.5 rounded border text-center"
          />
        </div>
      </div>

      <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
        <div className="bg-white p-3 rounded-lg border border-slate-100 shadow-sm">
          <span className="text-xs text-slate-400 block mb-1">Custo Total</span>
          <div className="text-lg font-medium text-slate-700">
            {formatMoney(costTotal)}
            {unidadeDeVenda === "square_meter" && <span className="text-xs text-slate-400"> /m²</span>}
          </div>
        </div>
        
        <div className="bg-white p-3 rounded-lg border border-slate-100 shadow-sm relative group">
          <span className="text-xs text-slate-400 block mb-1 flex items-center gap-1">
            Preço Sugerido
            <InfoTooltip text={`Margem alvo de ${category?.pricing_rule?.marginTargetPct ?? 50}% (da categoria) já descontando os ${variaveisPct.toFixed(1)}% que saem de cada venda em impostos e taxas${custoFixoUnitario > 0 ? ` e os ${formatMoney(custoFixoUnitario)} de custos fixos pelo tempo da ficha` : ""} — a mesma conta da tela de precificação.`} />
          </span>
          <div className="text-lg font-medium text-[var(--ks-color-primary)]">
            {formatMoney(suggestion.suggestedPrice)}
            {unidadeDeVenda === "square_meter" && <span className="text-xs text-slate-400"> /m²</span>}
          </div>
          <button 
            type="button"
            onClick={() => onApplyPrice(suggestion.suggestedPrice)}
            className="absolute right-2 top-2 text-[10px] bg-[var(--ks-color-primary)] text-white px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity"
          >
            Aplicar
          </button>
        </div>

        <div className={`p-3 rounded-lg border shadow-sm ${
          isPriceBelowCost ? "bg-rose-50 border-rose-200" :
          isMarginLow ? "bg-amber-50 border-amber-200" :
          "bg-emerald-50 border-emerald-200"
        }`}>
          <span className={`text-xs block mb-1 flex items-center gap-1 ${
             isPriceBelowCost ? "text-rose-600" :
             isMarginLow ? "text-amber-600" :
             "text-emerald-600"
          }`}>
            Margem Atual
            <InfoTooltip text={`(Preço − Custo${custoFixoUnitario > 0 ? " − fixos pelo tempo" : ""} − ${variaveisPct.toFixed(1)}% de impostos e taxas) ÷ Preço. É o que sobra de verdade. Mínimo da categoria: ${category?.pricing_rule?.marginMinPct ?? 35}%`} />
          </span>
          <div className={`text-lg font-medium ${
             isPriceBelowCost ? "text-rose-700" :
             isMarginLow ? "text-amber-700" :
             "text-emerald-700"
          }`}>
            {currentMargin.toFixed(1)}%
          </div>
        </div>
      </div>

      {suggestion.warnings.length > 0 && (
        <div className="text-xs text-amber-600 bg-amber-50 p-2 rounded">
          {suggestion.warnings.join(" ")}
        </div>
      )}
    </div>
  );
}
  /**
 * Abas do editor de produto. Centralizadas para a barra ser montada por map:
 * antes eram 7 blocos JSX quase identicos, com as mesmas ~10 classes repetidas.
 */
const ABAS_PRODUTO = [
  { value: "general", label: "Dados Gerais", icone: Package },
  { value: "composition", label: "Composição (Custos)", icone: Calculator },
  { value: "variations", label: "Variações", icone: Layers },
  { value: "tiers", label: "Preço por quantidade", icone: BadgeDollarSign },
  { value: "custom-fields", label: "Campos Personalizados", icone: Settings2 },
  { value: "combos", label: "Compre Junto", icone: Blocks },
  { value: "logistics", label: "Logística", icone: Truck },
  { value: "production", label: "Produção", icone: Clock3 },
] as const;

/* Estoque novo (v2): a aba Estoque entra logo depois da Composição. */
const ABAS_COM_ESTOQUE = [
  ...ABAS_PRODUTO.slice(0, 2),
  { value: "estoque", label: "Estoque", icone: Boxes },
  ...ABAS_PRODUTO.slice(2),
] as const;

export default function EditProductPage(props: { params: Promise<{ id: string }> }) {
  const { pode } = usePermissoes();
  /* Custo e margem sao dado comercial; o preco de venda nao passa por aqui. */
  const podeVerCustos = pode("pricing.read");
  const podeMexerNoCusto = pode("pricing.config.write");

  const searchParams = useSearchParams();
  /* Estoque novo (v2): a aba Estoque substitui o cartão antigo de estoque. Fora
     do v2 a tela segue exatamente igual. */
  const estoqueNovo = useEstoqueV2();
  const noEstoqueV2 = estoqueNovo.v2 && !estoqueNovo.carregando;
  const abasDoProduto = noEstoqueV2 ? ABAS_COM_ESTOQUE : ABAS_PRODUTO;
  const [abaAtual, setAbaAtual] = useState<string>(() => searchParams.get("aba") || "general");
  const isNewMode = searchParams.get("mode") === "new";
  const isCatalogSource = searchParams.get("source") === "catalog";
  const backHref = isCatalogSource ? "/dashboard/catalog/products" : "/dashboard/products";
  const [loading, setLoading] = useState(false);
  const [fetching, setFetching] = useState(true);
  /* Os avisos da tela. A caixinha do navegador para de aparecer depois de
     algumas seguidas, e o aviso flutuante não tem onde aparecer nesta
     página: "Produto atualizado" nunca chegava a quem salvava. */
  const [erroDaTela, setErroDaTela] = useState<string | null>(null);
  const [avisoDaTela, setAvisoDaTela] = useState<string | null>(null);
  const [erroAoAbrir, setErroAoAbrir] = useState<string | null>(null);
  const avisosRef = useRef<HTMLDivElement | null>(null);

  /* O aviso nasce perto do Salvar; se a pessoa salvou com Enter lá embaixo,
     a tela sobe até ele. */
  useEffect(() => {
    if (erroDaTela || avisoDaTela) avisosRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" });
  }, [erroDaTela, avisoDaTela]);
  const [categories, setCategories] = useState<Category[]>([]);
  const [formData, setFormData] = useState({
    name: "",
    description: "",
    price: "",
    price_on_request: false,
    use_variation_price_only: false,
    /* Valor mínimo do item (migration 194): só em produto por m² ou metro. */
    valor_minimo_item: "",
    valor_minimo_orcamentos: true,
    valor_minimo_loja: true,
    valor_minimo_pdv: true,
    estimated_base_cost: "",
    stock: "",
    unit_type: "unit",
    category_id: "",
    image_url: "",
    show_in_catalog: true,
    catalog_color: "#ffffff",
    min_sale_qty_enabled: false,
    min_sale_qty: "",
    allowed_sale_qty_enabled: false,
    inventory_scope: "product" as "product" | "option" | "variant",
    inventory_attribute_name: "",
    allow_negative_stock: false,
    track_inventory: false,
    sku: "",
    barcode: "",
    shipping_weight_kg: "",
    shipping_width_cm: "",
    shipping_height_cm: "",
    shipping_length_cm: "",
    production_time_value: "",
    production_time_unit: "business_days",
    production_template_url: "",
    production_template_name: "",
    production_template_format: "pdf" as ProductionTemplateFormat,
    production_templates: [] as ProductionTemplateFormItem[],
  });

  const [productId, setProductId] = useState<string | null>(null);
  const [costTotal, setCostTotal] = useState(0);
  /* A medida de referência da precificação: sem ela a ficha (por peça) não
     vira custo por m². E os custos variáveis da venda, para a análise usar o
     mesmo motor do assistente. */
  const [refsDePrecificacao, setRefsDePrecificacao] = useState<{ w: number | null; h: number | null }>({ w: null, h: null });
  const [variaveisPct, setVariaveisPct] = useState(0);
  /* A hora da estrutura (R$/h) e os minutos da ficha por unidade de venda: é
     o par que faz os custos fixos entrarem na análise pelo tempo. */
  const [taxaEstrutura, setTaxaEstrutura] = useState(0);
  const [minutosFichaPorUnidade, setMinutosFichaPorUnidade] = useState(0);
  const [costBreakdown, setCostBreakdown] = useState({
    estimated: 0,
    processes: 0,
    materials: 0
  });

  useEffect(() => {
    fetch("/api/precificacao/preparo", { cache: "no-store" })
      .then((r) => r.json())
      .then((j) => {
        setVariaveisPct(Number(j?.custosVariaveis?.totalPct ?? 0));
        setTaxaEstrutura(Number(j?.horaDaEstrutura?.taxa ?? 0));
      })
      .catch(() => {});
  }, []);

  // Variations State
  const [attributes, setAttributes] = useState<ProductAttribute[]>([]);
  /* Serviços opcionais: o cadastro é da empresa (biblioteca), e o produto só
     diz o que oferece. Por isso são dois estados, não um. */
  const [gruposDeServico, setGruposDeServico] = useState<GrupoDeServicos[]>([]);
  const [servicosDaLoja, setServicosDaLoja] = useState<ServicoOpcional[]>([]);
  const [custosDeServico, setCustosDeServico] = useState<Record<string, CustoDoServico>>({});
  const [vinculosDeServico, setVinculosDeServico] = useState<VinculoDeServico[]>([]);
  const [carregandoServicos, setCarregandoServicos] = useState(true);

  /* A biblioteca de serviços da empresa e o que este produto oferece dela.
     Duas leituras separadas de propósito: a biblioteca é a mesma para todos os
     produtos, e o vínculo é a opinião deste. */
  useEffect(() => {
    let ativo = true;
    fetch("/api/catalog/servicos", { cache: "no-store" })
      .then((r) => (r.ok ? r.json() : null))
      .then((j) => {
        if (!ativo || !j) return;
        setGruposDeServico(lerGrupos(j.grupos));
        setServicosDaLoja(lerServicos(j.servicos));
        const custos: Record<string, CustoDoServico> = {};
        for (const [id, bruto] of Object.entries((j.custos ?? {}) as Record<string, unknown>)) {
          custos[id] = lerCusto(bruto);
        }
        setCustosDeServico(custos);
      })
      .catch(() => {})
      .finally(() => {
        if (ativo) setCarregandoServicos(false);
      });
    return () => {
      ativo = false;
    };
  }, []);

  useEffect(() => {
    if (!productId) return;
    let ativo = true;
    getSupabaseClient()
      .from("product_optional_services")
      .select("service_id,enabled")
      .eq("product_id", productId)
      .then((resposta: { data: unknown }) => {
        if (!ativo) return;
        setVinculosDeServico(lerVinculosDeServico(resposta.data));
      });
    return () => {
      ativo = false;
    };
  }, [productId]);
  const [variations, setVariations] = useState<ProductVariation[]>([]);
  const [customFields, setCustomFields] = useState<ProductCustomFieldConfig[]>([]);
  const [priceTiers, setPriceTiers] = useState<ProductPriceTier[]>([]);
  const [productImages, setProductImages] = useState<ProductImageItem[]>([]);
  const [videoDoProduto, setVideoDoProduto] = useState<VideoDoProdutoNoCadastro>(VIDEO_VAZIO);
  const [quantityIntervals, setQuantityIntervals] = useState<QuantityIntervalDraft[]>([]);
  const [newIntervalQty, setNewIntervalQty] = useState("");
  const [newIntervalPrice, setNewIntervalPrice] = useState("");
  const [editingIntervalId, setEditingIntervalId] = useState<string | null>(null);
  const [editingIntervalQty, setEditingIntervalQty] = useState("");
  const [editingIntervalPrice, setEditingIntervalPrice] = useState("");
  const [erroDoIntervalo, setErroDoIntervalo] = useState<string | null>(null);
  /* Os dados que a nota fiscal usa: tipo, NCM, CEST, origem e tributação. */
  const [dadosFiscais, setDadosFiscais] = useState<DadosFiscaisDoProduto>(DADOS_FISCAIS_VAZIOS);
  const [generalAccordionOpen, setGeneralAccordionOpen] = useState({
    characteristics: true,
    value: false,
    stock: false,
  });
  
  const [isInventoryModalOpen, setIsInventoryModalOpen] = useState(false);
  const [isCategoryModalOpen, setIsCategoryModalOpen] = useState(false);

  function parseMinSaleQtyInput(value: string) {
    const normalized = value.replace(",", ".").trim();
    if (!normalized) return null;
    const parsed = Number(normalized);
    if (!Number.isFinite(parsed) || parsed <= 0) return null;
    return Number(parsed.toFixed(3));
  }

  function parseShippingNumberInput(value: string, decimals: number) {
    const normalized = value.replace(",", ".").trim();
    if (!normalized) return null;
    const parsed = Number(normalized);
    if (!Number.isFinite(parsed) || parsed <= 0) return null;
    return Number(parsed.toFixed(decimals));
  }

  function normalizeProductionTemplates(value: unknown, fallback?: {
    production_template_url?: string | null;
    production_template_name?: string | null;
    production_template_format?: ProductionTemplateFormat | null;
  } | null) {
    const templates = Array.isArray(value)
      ? value
          .map((item) => {
            const row = item as Partial<ProductionTemplateFormItem> | null;
            const format =
              row?.format === "ai" || row?.format === "cdr" || row?.format === "pdf" || row?.format === "canva"
                ? row.format
                : null;
            const url = typeof row?.url === "string" ? row.url.trim() : "";
            const name = typeof row?.name === "string" ? row.name.trim() : "";
            if (!format || !url) return null;
            return {
              format,
              url,
              name: name || "Gabarito",
            } satisfies ProductionTemplateFormItem;
          })
          .filter((item): item is ProductionTemplateFormItem => Boolean(item))
      : [];

    if (templates.length > 0) return templates;

    const legacyUrl = typeof fallback?.production_template_url === "string" ? fallback.production_template_url.trim() : "";
    const legacyName = typeof fallback?.production_template_name === "string" ? fallback.production_template_name.trim() : "";
    const legacyFormat =
      fallback?.production_template_format === "ai" ||
      fallback?.production_template_format === "cdr" ||
      fallback?.production_template_format === "pdf"
        ? fallback.production_template_format
        : null;

    if (!legacyUrl || !legacyFormat) return [];
    return [
      {
        format: legacyFormat,
        url: legacyUrl,
        name: legacyName || "Gabarito",
      },
    ];
  }

  function upsertProductionTemplate(
    templates: ProductionTemplateFormItem[],
    nextItem: ProductionTemplateFormItem | null,
    format: ProductionTemplateFormat
  ) {
    const base = templates.filter((item) => item.format !== format);
    if (!nextItem) return base;
    return [...base, nextItem];
  }

  function findProductionTemplate(templates: ProductionTemplateFormItem[], format: ProductionTemplateFormat) {
    return templates.find((item) => item.format === format) || null;
  }

  const fetchCategories = useCallback(async () => {
    const supabase = getSupabaseClient();
    const {
      data: { user },
    } = await supabase.auth.getUser();
    if (!user) {
      setCategories([]);
      return;
    }
    const ctx = await getCompanyContext(supabase, user);
    const tenantIds = ctx.tenantIds?.length ? ctx.tenantIds : [user.id];
    const { data } = await supabase
      .from('categories')
      .select('id, name, pricing_rule')
      .in('user_id', tenantIds)
      .order('name');
    if (data) setCategories(data);
  }, []);

  const fetchProduct = useCallback(async (id: string) => {
    const supabase = getSupabaseClient();
    const {
      data: { user },
    } = await supabase.auth.getUser();
    if (!user) {
      setErroAoAbrir("Sua sessão terminou. Entre de novo para editar o produto.");
      setFetching(false);
      return;
    }
    const ctx = await getCompanyContext(supabase, user);
    const tenantIds = ctx.tenantIds?.length ? ctx.tenantIds : [user.id];
    const baseSelect =
      "*, product_processes(cost_total,minutes,setup_minutes,consumption_base), product_materials(cost_total,quando_sai), product_attributes(*), product_variations(*)";
    const selectWithExtras = `${baseSelect}, product_price_tiers(id,min_qty,max_qty,unit_price,sort_order,active), product_images(id,image_url,sort_order,is_primary)`;

    let { data, error } = await supabase
      .from("products")
      .select(selectWithExtras)
      .eq("id", id)
      .in("user_id", tenantIds)
      .single();

    if (error) {
      const message = String((error as { message?: unknown } | null)?.message ?? "").toLowerCase();
      const missingTiers = message.includes("product_price_tiers");
      const missingImages = message.includes("product_images");
      if (missingTiers || missingImages) {
        const fallbackFields = [
          baseSelect,
          missingTiers ? "" : "product_price_tiers(id,min_qty,max_qty,unit_price,sort_order,active)",
          missingImages ? "" : "product_images(id,image_url,sort_order,is_primary)",
        ]
          .filter(Boolean)
          .join(", ");
        const fallback = await supabase
          .from("products")
          .select(fallbackFields)
          .eq("id", id)
          .in("user_id", tenantIds)
          .single();
        data = fallback.data as typeof data;
        error = fallback.error as typeof error;
      }
    }

    if (error || !data) {
      console.error("Error fetching product:", error);
      setErroAoAbrir("Não encontramos este produto. Ele pode ter sido excluído.");
      setFetching(false);
      return;
    }

    /* Produto digital mora na área Produtos digitais: este editor (de produto
       físico, com estoque e frete) não abre ele. */
    if ((data as { product_kind?: unknown }).product_kind === "digital") {
      window.location.replace(`/dashboard/digitais/produtos/${id}`);
      return;
    }

    /* Produto novo: o rascunho nasce fora da vitrine (products/new), para não
       aparecer na loja como "Novo produto" se a pessoa desistir no meio. Aqui
       o editor já mostra "Exibir na vitrine" ligado, que é o padrão e o que
       vale quando ela salvar pela primeira vez. */
    const rascunhoNovo = new URLSearchParams(window.location.search).get("mode") === "new";

    setFormData({
      name: data.name,
      description: descriptionToEditorHtml(data.description || ""),
      price_on_request: Boolean((data as { price_on_request?: boolean | null } | null)?.price_on_request),
      use_variation_price_only: Boolean((data as { use_variation_price_only?: boolean | null } | null)?.use_variation_price_only),
      valor_minimo_item:
        Number((data as { valor_minimo_item?: number | string | null }).valor_minimo_item) > 0
          ? formatMoneyInput(Number((data as { valor_minimo_item?: number | string | null }).valor_minimo_item))
          : "",
      valor_minimo_orcamentos: (data as { valor_minimo_orcamentos?: boolean | null }).valor_minimo_orcamentos !== false,
      valor_minimo_loja: (data as { valor_minimo_loja?: boolean | null }).valor_minimo_loja !== false,
      valor_minimo_pdv: (data as { valor_minimo_pdv?: boolean | null }).valor_minimo_pdv !== false,
      price: Boolean((data as { price_on_request?: boolean | null } | null)?.price_on_request)
        ? ""
        : formatMoneyInput(data.price),
      estimated_base_cost: formatMoneyInput(data.estimated_base_cost),
      stock: data.stock.toString(),
      unit_type: data.unit_type || "unit",
      category_id: data.category_id || "",
      image_url: data.image_url || "",
      show_in_catalog: rascunhoNovo || data.show_in_catalog !== false,
      catalog_color: data.catalog_color || "#ffffff",
      min_sale_qty_enabled: Boolean(
        (data as { min_sale_qty_enabled?: boolean | null } | null)?.min_sale_qty_enabled
      ),
      min_sale_qty:
        (data as { min_sale_qty?: number | null } | null)?.min_sale_qty != null
          ? String((data as { min_sale_qty?: number | null }).min_sale_qty)
          : "",
      allowed_sale_qty_enabled: Boolean(
        (data as { allowed_sale_qty_enabled?: boolean | null } | null)?.allowed_sale_qty_enabled
      ),
      inventory_scope:
        (data as { inventory_scope?: "product" | "option" | "variant" | null } | null)?.inventory_scope || "product",
      inventory_attribute_name:
        (data as { inventory_attribute_name?: string | null } | null)?.inventory_attribute_name || "",
      allow_negative_stock: Boolean(
        (data as { allow_negative_stock?: boolean | null } | null)?.allow_negative_stock
      ),
      track_inventory: Boolean(
        (data as { track_inventory?: boolean | null } | null)?.track_inventory
      ),
      sku: (data as { sku?: string | null } | null)?.sku || "",
      barcode: (data as { barcode?: string | null } | null)?.barcode || "",
      shipping_weight_kg:
        (data as { shipping_weight_kg?: number | null } | null)?.shipping_weight_kg != null
          ? String((data as { shipping_weight_kg?: number | null }).shipping_weight_kg)
          : "",
      shipping_width_cm:
        (data as { shipping_width_cm?: number | null } | null)?.shipping_width_cm != null
          ? String((data as { shipping_width_cm?: number | null }).shipping_width_cm)
          : "",
      shipping_height_cm:
        (data as { shipping_height_cm?: number | null } | null)?.shipping_height_cm != null
          ? String((data as { shipping_height_cm?: number | null }).shipping_height_cm)
          : "",
      shipping_length_cm:
        (data as { shipping_length_cm?: number | null } | null)?.shipping_length_cm != null
          ? String((data as { shipping_length_cm?: number | null }).shipping_length_cm)
          : "",
      production_time_value:
        (data as { production_time_value?: number | null } | null)?.production_time_value != null
          ? String((data as { production_time_value?: number | null }).production_time_value)
          : "",
      production_time_unit:
        (data as { production_time_unit?: string | null } | null)?.production_time_unit || "business_days",
      production_template_url:
        (data as { production_template_url?: string | null } | null)?.production_template_url || "",
      production_template_name:
        (data as { production_template_name?: string | null } | null)?.production_template_name || "",
      production_template_format:
        (data as { production_template_format?: "pdf" | "ai" | "cdr" | null } | null)?.production_template_format || "pdf",
      production_templates: normalizeProductionTemplates(
        (data as { production_templates?: unknown } | null)?.production_templates,
        {
          production_template_url: (data as { production_template_url?: string | null } | null)?.production_template_url || null,
          production_template_name: (data as { production_template_name?: string | null } | null)?.production_template_name || null,
          production_template_format: (data as { production_template_format?: ProductionTemplateFormat | null } | null)?.production_template_format || null,
        }
      ),
    });

    setDadosFiscais(lerDadosFiscaisDoProduto(data as unknown as Record<string, unknown>));
    setVideoDoProduto(videoDoProdutoSalvo(data as unknown as Record<string, unknown>));

    setQuantityIntervals(
      hydrateQuantityIntervalsFromProduct({
        allowedQuantities: (data as { allowed_sale_quantities?: unknown } | null)?.allowed_sale_quantities,
        tiers: ((data as { product_price_tiers?: ProductPriceTier[] | null } | null)?.product_price_tiers || []),
        fallbackUnitPrice: Number((data as { price?: number | null } | null)?.price || 0),
      })
    );

    const mappedImages = ((data as { product_images?: Array<Record<string, unknown>> | null } | null)?.product_images || [])
      .map((image, index) => ({
        id: typeof image.id === "string" ? image.id : crypto.randomUUID(),
        image_url: typeof image.image_url === "string" ? image.image_url : "",
        sort_order: typeof image.sort_order === "number" ? image.sort_order : index,
        is_primary: Boolean(image.is_primary),
      }))
      .filter((image) => Boolean(image.image_url))
      .sort((a, b) => a.sort_order - b.sort_order)
      .map((image, index) => ({ ...image, sort_order: index }));

    if (mappedImages.length > 0) {
      const hasPrimary = mappedImages.some((image) => image.is_primary);
      const normalized = mappedImages.map((image, index) => ({
        ...image,
        is_primary: hasPrimary ? image.is_primary : index === 0,
      }));
      setProductImages(normalized);
    } else if (data.image_url) {
      setProductImages([
        {
          id: crypto.randomUUID(),
          image_url: data.image_url,
          sort_order: 0,
          is_primary: true,
        },
      ]);
    } else {
      setProductImages([]);
    }
    
    const processesCost = ((data.product_processes as Array<{ cost_total?: number | null }> | null) || []).reduce(
      (acc, p) => acc + (Number(p.cost_total) || 0),
      0
    );
    /* Estoque v2: linha "só se a opção X" não entra no custo base (só vale
       quando a opção é escolhida). Fora do v2 nenhuma linha é `se_opcao`. */
    const materialsCost = custoBaseDaComposicao(
      (data.product_materials as Array<{ cost_total?: number | null; quando_sai?: "sempre" | "pela_variacao" | "se_opcao" | "so_custo" | null }> | null) || []
    );
    const estimatedCost = Number(data.estimated_base_cost ?? 0);
    
    setCostBreakdown({
      estimated: estimatedCost,
      processes: processesCost,
      materials: materialsCost
    });
    const refW = Number(data.pricing_reference_width_m ?? 0) || null;
    const refH = Number(data.pricing_reference_height_m ?? 0) || null;
    setRefsDePrecificacao({ w: refW, h: refH });
    /* Os minutos da ficha na unidade de venda, no espelho da conta do custo:
       por peça de referência, ÷ área quando o produto é medido. É por eles
       que a análise carrega os custos fixos pelo tempo. */
    const minutosDaFicha = ((data.product_processes as Array<{
      minutes?: number | null; setup_minutes?: number | null; consumption_base?: string | null;
    }> | null) || []).reduce((acc, p) => {
      const base = (p.consumption_base ?? "por_peca") as BaseDeConsumo;
      const medida = medidaDaBase(base, refW ?? 0, refH ?? 0);
      if (base !== "por_peca" && medida <= 0) return acc;
      return acc + (Number(p.minutes) || 0) * medida + (Number(p.setup_minutes) || 0);
    }, 0);
    const areaRef = (refW ?? 0) * (refH ?? 0);
    setMinutosFichaPorUnidade(
      data.unit_type === "square_meter" && areaRef > 0 ? minutosDaFicha / areaRef : minutosDaFicha
    );
    /* A conta ciente de unidade: a ficha é por peça de referência, e no
       produto medido a unidade de venda é o m². A soma cega dobrava o custo do
       banner nascido no assistente. */
    setCostTotal(custoDoProduto({
      estimatedBaseCost: estimatedCost,
      somaDaFicha: processesCost + materialsCost,
      unitType: data.unit_type,
      referenceWidthM: refW,
      referenceHeightM: refH,
    }));
    
    // Load variations data
    if (data.product_attributes) {
      /* O saldo por opção exibido é o VIVO (product_option_stocks, que as
         vendas movimentam) — o número gravado no JSON do atributo é só o
         chute inicial e fica para trás a cada venda. */
      const { data: liveOptionStocks } = await supabase
        .from("product_option_stocks")
        .select("option_id,stock,minimum_stock,reorder_point")
        .eq("product_id", id)
        .eq("active", true);
      const liveByOptionId = new Map(
        ((liveOptionStocks as Array<{ option_id?: string | null; stock?: number | null; minimum_stock?: number | null; reorder_point?: number | null }> | null) || [])
          .filter((row) => typeof row.option_id === "string" && row.option_id)
          .map((row) => [String(row.option_id), row])
      );
      // Receita da opção: o vínculo opção → insumo vive em tabela própria.
      const { data: liveRecipes } = await supabase
        .from("product_option_recipes")
        .select("option_id,material_id,qty_per_piece")
        .eq("product_id", id)
        .eq("active", true);
      const recipeByOptionId = new Map(
        ((liveRecipes as Array<{ option_id?: string | null; material_id?: string | null; qty_per_piece?: number | null }> | null) || [])
          .filter((row) => typeof row.option_id === "string" && row.option_id)
          .map((row) => [String(row.option_id), row])
      );
      const attributesData = data.product_attributes as Array<{
        id?: string | null;
        name?: string | null;
        options?: Array<string | ProductOption> | null;
        allow_multiple?: boolean | null;
        is_required?: boolean | null;
        position?: number | null;
        display_style?: string | null;
        show_in_store?: boolean | null;
      }>;
      setAttributes(
        attributesData
          .map((a, index) => ({
            id: a.id ?? undefined,
            name: a.name ?? "",
            options: Array.isArray(a.options)
              ? a.options.map((opt) => {
                  if (typeof opt === "string") {
                    return { label: opt, price: 0, is_required: false, price_applies_per_quantity: true };
                  }
                  const live = opt.id ? liveByOptionId.get(String(opt.id)) : undefined;
                  const recipe = opt.id ? recipeByOptionId.get(String(opt.id)) : undefined;
                  return {
                    ...opt,
                    ...(live
                      ? {
                          stock: Number(live.stock) || 0,
                          minimum_stock: Number(live.minimum_stock) || 0,
                          reorder_point: Number(live.reorder_point) || 0,
                        }
                      : {}),
                    material_id: recipe?.material_id ?? null,
                    material_qty: recipe ? Number(recipe.qty_per_piece) || 0 : 0,
                    price_applies_per_quantity: opt.price_applies_per_quantity !== false,
                  };
                })
              : [],
            allow_multiple: a.allow_multiple ?? false,
            is_required: a.is_required ?? false,
            position: a.position ?? index,
            display_style: a.display_style ?? null,
            /* Nasce mostrando: o que já existe continua na vitrine. */
            show_in_store: a.show_in_store !== false,
          }))
          .sort((a, b) => (a.position ?? 0) - (b.position ?? 0))
      );
    }
    
    const { data: isolatedVariationsData, error: isolatedVariationsError } = await supabase
      .from("product_variations")
      .select("id,combination,sku,price,stock,cost_adjustment,active")
      .eq("product_id", id)
      .eq("active", true);

    if (!isolatedVariationsError && Array.isArray(isolatedVariationsData)) {
      setVariations(
        isolatedVariationsData.map((v) => ({
          id: v.id ?? undefined,
          combination: (v.combination as Record<string, string> | null) ?? {},
          sku: v.sku || "",
          price: v.price ?? null,
          stock: v.stock ?? 0,
          cost_adjustment: v.cost_adjustment ?? 0,
        }))
      );
    } else if (data.product_variations) {
      const variationsData = data.product_variations as Array<{
        id?: string | null;
        combination?: Record<string, string> | null;
        sku?: string | null;
        price?: number | null;
        stock?: number | null;
        cost_adjustment?: number | null;
        active?: boolean | null;
      }>;
      setVariations(
        variationsData
          .filter((v) => v.active !== false)
          .map((v) => ({
            id: v.id ?? undefined,
            combination: v.combination ?? {},
            sku: v.sku || "",
            price: v.price ?? null,
            stock: v.stock ?? 0,
            cost_adjustment: v.cost_adjustment ?? 0,
          }))
      );
    }

    setCustomFields(
      normalizeProductCustomFieldsConfig(
        (data as { custom_fields_config?: unknown } | null)?.custom_fields_config
      )
    );

    if (data.product_price_tiers) {
      const tiersData = data.product_price_tiers as Array<{
        id?: string | null;
        min_qty?: number | null;
        max_qty?: number | null;
        unit_price?: number | null;
        sort_order?: number | null;
        active?: boolean | null;
      }>;
      setPriceTiers(
        tiersData
          .map((tier, index) => ({
            id: tier.id ?? undefined,
            min_qty: Number(tier.min_qty) || 0,
            max_qty: tier.max_qty === null || tier.max_qty === undefined ? null : Number(tier.max_qty) || 0,
            unit_price: Number(tier.unit_price) || 0,
            sort_order: typeof tier.sort_order === "number" ? tier.sort_order : index,
            active: tier.active ?? true,
          }))
          .sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0))
      );
    } else {
      setPriceTiers([]);
    }

    setFetching(false);
  }, []);

  useEffect(() => {
    let cancelled = false;

    async function init() {
      const params = await props.params;
      if (cancelled) return;
      setProductId(params.id);
      await fetchCategories();
      await fetchProduct(params.id);
    }
    init();

    return () => {
      cancelled = true;
    };
  }, [fetchCategories, fetchProduct, props.params]);

  function handleProductImagesChange(nextImages: ProductImageItem[]) {
    setProductImages(nextImages);
    setFormData((prev) => ({
      ...prev,
      image_url: getPrimaryProductImageUrl(nextImages, prev.image_url),
    }));
  }

  const parsedQuantityIntervals = useMemo(
    () => parseQuantityIntervalsDrafts(quantityIntervals),
    [quantityIntervals]
  );
  const intervalPricingPreview = useMemo(
    () => buildAllowedQuantityPricing(parsedQuantityIntervals.intervals),
    [parsedQuantityIntervals.intervals]
  );

  function addQuantityInterval() {
    const nextDraft = createQuantityIntervalDraft({
      quantity: newIntervalQty,
      price: newIntervalPrice,
    });
    const parsed = parseQuantityIntervalsDrafts([nextDraft]);
    if (parsed.error) {
      setErroDoIntervalo(parsed.error);
      return;
    }
    if (parsed.intervals.length === 0) {
      setErroDoIntervalo("Preencha a quantidade e o valor antes de adicionar.");
      return;
    }
    const nextQuantity = parsed.intervals[0].quantity;

    const alreadyExists = quantityIntervals.some((interval) => {
      const current = parseQuantityIntervalsDrafts([interval]);
      return (
        !current.error &&
        current.intervals.length > 0 &&
        Math.abs(current.intervals[0].quantity - nextQuantity) <= 0.000001
      );
    });
    if (alreadyExists) {
      setErroDoIntervalo("Já existe um card com essa quantidade.");
      return;
    }

    setQuantityIntervals((prev) => [...prev, nextDraft]);
    setNewIntervalQty("");
    setNewIntervalPrice("");
    setErroDoIntervalo(null);
  }

  function removeQuantityInterval(id: string) {
    setQuantityIntervals((prev) => prev.filter((interval) => interval.id !== id));
  }

  function startEditQuantityInterval(interval: QuantityIntervalDraft) {
    setEditingIntervalId(interval.id);
    setEditingIntervalQty(interval.quantity ?? "");
    setEditingIntervalPrice(interval.price ?? "");
  }

  function saveEditQuantityInterval(id: string) {
    const nextDraft = createQuantityIntervalDraft({
      quantity: editingIntervalQty,
      price: editingIntervalPrice,
    });
    const parsed = parseQuantityIntervalsDrafts([nextDraft]);
    if (parsed.error) {
      setErroDoIntervalo(parsed.error);
      return;
    }
    if (parsed.intervals.length === 0) {
      setErroDoIntervalo("Preencha a quantidade e o valor antes de salvar.");
      return;
    }

    const nextQuantity = parsed.intervals[0].quantity;
    const alreadyExists = quantityIntervals.some((interval) => {
      if (interval.id === id) return false;
      const current = parseQuantityIntervalsDrafts([interval]);
      return (
        !current.error &&
        current.intervals.length > 0 &&
        Math.abs(current.intervals[0].quantity - nextQuantity) <= 0.000001
      );
    });
    if (alreadyExists) {
      setErroDoIntervalo("Já existe um card com essa quantidade.");
      return;
    }

    setQuantityIntervals((prev) =>
      prev.map((interval) =>
        interval.id === id
          ? { ...interval, quantity: nextDraft.quantity, price: nextDraft.price }
          : interval
      )
    );
    setEditingIntervalId(null);
    setEditingIntervalQty("");
    setEditingIntervalPrice("");
    setErroDoIntervalo(null);
  }

  function handleOptionStockUpdate(optionId: string, newStock: number) {
    setAttributes((prev) =>
      prev.map((attribute) => ({
        ...attribute,
        options: (attribute.options || []).map((option) => {
          if (!option || typeof option === "string") return option;
          if (option.id !== optionId) return option;
          return { ...option, stock: newStock };
        }),
      }))
    );
  }

  function handleVariationStockUpdate(variationId: string, newStock: number) {
    setVariations((prev) =>
      prev.map((variation) => (variation.id === variationId ? { ...variation, stock: newStock } : variation))
    );
  }

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setErroDaTela(null);
    setAvisoDaTela(null);
    if (!productId) return;
    setLoading(true);
    /* Toda saída antes do envio devolve o botão. Antes, dois avisos do
       estoque saíam sem isso e o Salvar ficava preso em "Salvando..." até
       recarregar a página, perdendo o que tinha sido editado. */
    const recusar = (texto: string) => {
      setErroDaTela(texto);
      setLoading(false);
    };
    
    if (
      !formData.price_on_request &&
      !formData.allowed_sale_qty_enabled &&
      !formData.use_variation_price_only &&
      !formData.price
    ) {
      recusar("Informe o preço de venda. Se ele depende de cada pedido, ligue “Sob consulta”.");
      return;
    }
    
    const price = parseMoneyInput(formData.price);
    const estimatedBaseCost = parseMoneyInput(formData.estimated_base_cost);
    const minSaleQty = parseMinSaleQtyInput(formData.min_sale_qty);
    const shippingWeightKg = parseShippingNumberInput(formData.shipping_weight_kg, 3);
    const shippingWidthCm = parseShippingNumberInput(formData.shipping_width_cm, 2);
    const shippingHeightCm = parseShippingNumberInput(formData.shipping_height_cm, 2);
    const shippingLengthCm = parseShippingNumberInput(formData.shipping_length_cm, 2);
    const productionTimeValue = parseMinSaleQtyInput(formData.production_time_value);
    const preferredLegacyTemplate =
      findProductionTemplate(formData.production_templates, "pdf") ||
      findProductionTemplate(formData.production_templates, "ai") ||
      findProductionTemplate(formData.production_templates, "cdr");

    if (parsedQuantityIntervals.error) {
      recusar(parsedQuantityIntervals.error);
      return;
    }

    if (formData.allowed_sale_qty_enabled && parsedQuantityIntervals.intervals.length === 0) {
      recusar("Adicione ao menos um card de quantidade + valor.");
      return;
    }

    if (formData.min_sale_qty_enabled && minSaleQty === null) {
      recusar("Informe uma quantidade mínima de venda válida.");
      return;
    }

    if (formData.production_time_value.trim() && productionTimeValue === null) {
      recusar("Informe um prazo de produção válido.");
      return;
    }

    const derivedIntervalPricing = intervalPricingPreview;
    const allowedSaleQuantities = formData.allowed_sale_qty_enabled ? derivedIntervalPricing.allowedQuantities : [];
    const tiersToPersist = formData.allowed_sale_qty_enabled ? derivedIntervalPricing.tiers : priceTiers;

    if (!formData.price_on_request) {
      const tierValidation = validatePriceTiersAgainstSaleLimits(tiersToPersist, {
        min_sale_qty_enabled: formData.min_sale_qty_enabled,
        min_sale_qty: formData.min_sale_qty_enabled ? minSaleQty : null,
        max_sale_qty_enabled: false,
        max_sale_qty: null,
        allowed_sale_qty_enabled: formData.allowed_sale_qty_enabled,
        allowed_sale_quantities: allowedSaleQuantities,
      });
      if (tierValidation.error) {
        recusar(tierValidation.error);
        return;
      }
    }
    if (!noEstoqueV2 && formData.track_inventory && formData.inventory_scope === "option" && !(formData.inventory_attribute_name || "").trim()) {
      recusar("Com estoque por opção, escolha qual atributo controla o estoque (ex.: Cor) no card Estoque.");
      return;
    }
    if (!noEstoqueV2 && formData.track_inventory && formData.inventory_scope === "variant") {
      const multiplos = attributes.filter((a) => a.allow_multiple).map((a) => a.name || "atributo");
      if (multiplos.length > 0) {
        recusar(
          `Com estoque por combinação, cada atributo aceita uma escolha só — senão a baixa não sabe qual combinação usar. Desligue "Múltipla escolha" em: ${multiplos.join(", ")}.`
        );
        return;
      }
    }

    const problemaFiscal = problemaNosDadosFiscais(dadosFiscais);
    if (problemaFiscal) {
      recusar(problemaFiscal);
      return;
    }

    const res = await fetch("/api/products", {
      method: "PATCH",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
          id: productId,
          patch: {
            name: formData.name,
            description: formData.description,
            price: formData.price_on_request ? 0 : (isNaN(price) ? 0 : price),
            price_on_request: formData.price_on_request,
            use_variation_price_only: formData.use_variation_price_only,
            valor_minimo_item: parseMoneyInput(formData.valor_minimo_item) > 0 ? parseMoneyInput(formData.valor_minimo_item) : null,
            valor_minimo_orcamentos: formData.valor_minimo_orcamentos,
            valor_minimo_loja: formData.valor_minimo_loja,
            valor_minimo_pdv: formData.valor_minimo_pdv,
            estimated_base_cost: isNaN(estimatedBaseCost) ? 0 : estimatedBaseCost,
            unit_type: formData.unit_type,
            category_id: formData.category_id || null,
            image_url: getPrimaryProductImageUrl(productImages, formData.image_url) || null,
            images: productImages,
            ...videoParaSalvar(videoDoProduto),
            show_in_catalog: formData.show_in_catalog,
            catalog_color: formData.catalog_color,
            min_sale_qty_enabled: formData.min_sale_qty_enabled,
            min_sale_qty: formData.min_sale_qty_enabled ? minSaleQty : null,
            max_sale_qty_enabled: false,
            max_sale_qty: null,
            allowed_sale_qty_enabled: formData.allowed_sale_qty_enabled,
            allowed_sale_quantities: formData.allowed_sale_qty_enabled ? allowedSaleQuantities : null,
            sku: formData.sku || null,
            barcode: formData.barcode || null,
            ...patchFiscalDoProduto(dadosFiscais),
            shipping_weight_kg: shippingWeightKg,
            shipping_width_cm: shippingWidthCm,
            shipping_height_cm: shippingHeightCm,
            shipping_length_cm: shippingLengthCm,
            production_time_value: productionTimeValue,
            production_time_unit: productionTimeValue ? formData.production_time_unit : null,
            production_template_url: preferredLegacyTemplate?.url || null,
            production_template_name: preferredLegacyTemplate?.name || null,
            production_template_format: preferredLegacyTemplate?.format || null,
            production_templates: formData.production_templates,
            /* No estoque novo quem decide isto é a aba Estoque (estoque_configurar_produto):
               o salvar do produto não regrava o controle antigo. */
            ...(noEstoqueV2
              ? {}
              : {
                  track_inventory: formData.track_inventory,
                  inventory_scope: formData.inventory_scope,
                  inventory_attribute_name:
                    formData.inventory_scope === "option" ? (formData.inventory_attribute_name || null) : null,
                  allow_negative_stock: formData.allow_negative_stock,
                }),
            attributes,
            variations,
            custom_fields_config: customFields,
            optional_service_links: vinculosDeServico.map((v) => ({ service_id: v.serviceId, enabled: v.ligado })),
            price_tiers: tiersToPersist,
          },
        }),
    }).catch(() => null);

    if (!res) {
      recusar("Não foi possível falar com o sistema. Confira a internet e tente de novo.");
      return;
    }

    const json = (await res.json().catch(() => null)) as { error?: string } | null;
    if (!res.ok) {
      setErroDaTela("Não foi possível salvar: " + (json?.error || "falha ao atualizar o produto."));
    } else {
      setAvisoDaTela("Produto salvo.");
      /* Salvo uma vez, deixou de ser rascunho: o endereço perde o "mode=new"
         para quem recarregar a página ver o que foi gravado (inclusive a
         vitrine desligada, se foi a escolha). */
      if (isNewMode) {
        const endereco = new URL(window.location.href);
        endereco.searchParams.delete("mode");
        window.history.replaceState(window.history.state, "", `${endereco.pathname}${endereco.search}`);
      }
    }
    setLoading(false);
  }

  if (erroAoAbrir) {
    return (
      <div className="ks-page pb-20">
        <div className="ks-surface flex min-h-[320px] flex-col items-center justify-center gap-4 p-6 text-center">
          <p className="text-base font-semibold text-[var(--ks-color-text-primary)]">{erroAoAbrir}</p>
          <Link href={backHref}>
            <Button variant="outline" size="sm" icon={<Package size={16} />}>
              Voltar para lista
            </Button>
          </Link>
        </div>
      </div>
    );
  }

  if (fetching) {
    return (
      <div className="ks-page pb-20">
        <div className="ks-surface flex items-center justify-center min-h-[320px]">
          <Loader2 className="w-6 h-6 animate-spin text-[var(--ks-color-primary)]" />
        </div>
      </div>
    );
  }

  return (
    <div className="ks-page pb-20 space-y-6">
      <PageHeader
        eyebrow="Produtos"
        title={isNewMode ? (isCatalogSource ? "Novo produto do catálogo" : "Novo produto") : "Editar produto"}
        subtitle={
          isNewMode
            ? "Use o mesmo editor completo da edição para configurar o produto do seu jeito."
            : "Ajuste nome, preço, estoque e como o item aparece no catálogo público."
        }
        actions={
          <Link href={backHref}>
            <Button variant="ghost" size="sm" icon={<Package size={16} />}>
              Voltar para lista
            </Button>
          </Link>
        }
      />

      <div className="ks-surface p-6">
        <form onSubmit={handleSubmit} className="space-y-6">
          <div className="flex items-center justify-between gap-4">
            <Link href={backHref} className="ks-button ks-button-ghost px-3 py-2">
              <ArrowLeft size={16} />
              <span>Voltar</span>
            </Link>
            <Button
              type="submit"
              size="md"
              disabled={loading}
              icon={loading ? <Loader2 className="w-4 h-4 animate-spin" /> : <Save className="w-4 h-4" />}
            >
              {loading ? "Salvando..." : "Salvar alterações"}
            </Button>
          </div>

          {erroDaTela || avisoDaTela ? (
            <div ref={avisosRef} className="space-y-3">
              {erroDaTela ? (
                <Aviso tom="ruim" aoFechar={() => setErroDaTela(null)}>
                  {erroDaTela}
                </Aviso>
              ) : null}
              {avisoDaTela ? (
                <Aviso tom="bom" aoFechar={() => setAvisoDaTela(null)}>
                  {avisoDaTela}
                </Aviso>
              ) : null}
            </div>
          ) : null}

          <Tabs value={abaAtual} onValueChange={setAbaAtual} className="w-full">
            {/*
              Antes: flex-nowrap + overflow-x-auto, o que forcava rolagem
              horizontal sempre que as 7 abas nao cabiam. Agora elas quebram
              em linhas e a barra se adapta a qualquer largura sem rolagem.
            */}
            <TabsList className="mb-6 flex h-auto w-full flex-wrap justify-start gap-1 rounded-[var(--ks-radius-md)] border-0 bg-[var(--ks-color-bg-soft)] p-1.5 shadow-none">
              {abasDoProduto.map((aba) => {
                const Icone = aba.icone;
                return (
                  <TabsTrigger
                    key={aba.value}
                    value={aba.value}
                    disabled={aba.value === "tiers" && formData.allowed_sale_qty_enabled}
                    className="group flex items-center gap-2 whitespace-nowrap rounded-[var(--ks-radius-xs)] px-3 py-2 text-[13px] font-semibold text-[var(--ks-color-text-muted)] transition-colors hover:bg-white hover:text-[var(--ks-color-text-primary)] data-[state=active]:bg-[var(--ks-brand-600)] data-[state=active]:text-white data-[state=active]:shadow-[0_4px_12px_-4px_rgba(95,49,214,0.5)] disabled:pointer-events-none disabled:opacity-40"
                  >
                    <Icone size={15} strokeWidth={2} className="shrink-0 opacity-70 group-data-[state=active]:opacity-100" />
                    {aba.value === "tiers" && vendidoPorMedida(formData.unit_type)
                      ? `Faixas por ${nomeDaMedida(formData.unit_type)}`
                      : aba.label}
                  </TabsTrigger>
                );
              })}
            </TabsList>

            <TabsContent value="general">
              <div className="grid grid-cols-1 lg:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)] gap-6">
            <div className="space-y-4">
              <div className="rounded-[20px] border border-slate-200/60 bg-white shadow-[0_2px_14px_rgba(0,0,0,0.02)] overflow-hidden transition-all duration-300 hover:border-slate-300/80 hover:shadow-[0_8px_30px_rgba(0,0,0,0.06)]">
                <button
                  type="button"
                  onClick={() =>
                    setGeneralAccordionOpen((prev) => ({ ...prev, characteristics: !prev.characteristics }))
                  }
                  className="w-full flex items-center justify-between gap-4 px-6 py-5 text-left bg-transparent transition-colors hover:bg-slate-50/50"
                >
                  <span className="flex items-center gap-3">
                    <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-slate-50 text-[var(--ks-color-primary-strong)] border border-slate-100 shadow-[0_2px_4px_rgba(0,0,0,0.02)]">
                      <Info size={16} />
                    </span>
                    <span className="min-w-0">
                      <span className="block text-[15px] font-bold text-slate-800 tracking-tight">Características</span>
                      <span className="block text-[13px] font-medium text-slate-500 mt-0.5">Nome, categoria, unidade e descrição</span>
                    </span>
                  </span>
                  <ChevronDown
                    size={18}
                    className={`text-[var(--ks-color-text-soft)] transition-transform duration-200 ${generalAccordionOpen.characteristics ? "rotate-180" : ""}`}
                  />
                </button>
                <div className={`grid transition-all duration-200 ease-out ${generalAccordionOpen.characteristics ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"}`}>
                  <div className="overflow-hidden">
                    <div className="border-t border-[rgba(198,203,224,0.4)] p-5 space-y-5">
                    <Input
                      label="Nome do produto"
                      placeholder="Ex: Camiseta básica"
                      value={formData.name}
                      onChange={(e) => setFormData({ ...formData, name: e.target.value })}
                      required
                    />
                    <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                      <div className="space-y-2">
                        <div className="flex items-center justify-between">
                          <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                            Categoria
                          </label>
                          <button
                            type="button"
                            onClick={() => setIsCategoryModalOpen(true)}
                            className="inline-flex items-center gap-1.5 text-xs font-medium text-[var(--ks-color-primary)] hover:underline"
                          >
                            <Plus size={12} />
                            Nova categoria
                          </button>
                        </div>
                        <CustomSelect
                          options={[
                            { value: "", label: "Sem categoria" },
                            ...categories
                              .filter((cat) => cat.id)
                              .map((cat) => ({ value: cat.id, label: cat.name })),
                          ]}
                          value={formData.category_id}
                          onChange={(value) => setFormData({ ...formData, category_id: value })}
                          placeholder="Selecione..."
                          searchable
                        />
                      </div>
                      <div className="space-y-2">
                        <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                          Unidade de medida
                        </label>
                        <CustomSelect
                          options={[
                            { value: "unit", label: "Unidade" },
                            { value: "meter", label: "Metro" },
                            { value: "linear_meter", label: "Metro Linear" },
                            { value: "square_meter", label: "Metro Quadrado" },
                            { value: "box", label: "Caixa" },
                            { value: "ream", label: "Resma" },
                          ]}
                          value={formData.unit_type}
                          onChange={(value) => setFormData({ ...formData, unit_type: value })}
                        />
                      </div>
                      {/* Produto por m²: o lojista precisa saber, aqui mesmo, o que
                          muda no preço, nas faixas e nos adicionais. */}
                      {vendidoPorMedida(formData.unit_type) && (
                        <div className="md:col-span-2 space-y-1 rounded-xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-inset)] px-4 py-3 text-xs text-[var(--ks-color-text-secondary)]">
                          <p className="font-semibold text-[var(--ks-color-text-primary)]">
                            Produto vendido por {nomeDaMedida(formData.unit_type)}
                          </p>
                          <p>
                            O preço acima é o preço de 1 {nomeDaMedida(formData.unit_type)}. Na loja o cliente informa a medida e
                            quantas peças quer; o sistema calcula {nomeDaMedida(formData.unit_type)} × peças.
                          </p>
                          <p>
                            As faixas de preço (aba Faixas por {nomeDaMedida(formData.unit_type)}) valem pela {formData.unit_type === "square_meter" ? "área" : "metragem"} total
                            do pedido, não pelo número de peças.
                          </p>
                          <p>
                            Nos adicionais das variações você escolhe se o valor é por {nomeDaMedida(formData.unit_type)}, por peça ou
                            uma vez no pedido.
                          </p>
                        </div>
                      )}
                    </div>
                    <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                      <div className="space-y-2">
                        <Input
                          label="SKU (Código Ref interno)"
                          name="sku"
                          placeholder="Ex: CAM-BASC-01"
                          value={formData.sku}
                          onChange={(e) => setFormData({ ...formData, sku: e.target.value })}
                        />
                        <div className="mt-2 text-left">
                          <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            className="text-xs h-8 px-3"
                            icon={<Dices size={14} />}
                            onClick={() => {
                              const nameParts = (formData.name || "")
                                .normalize("NFD")
                                .replace(/[\u0300-\u036f]/g, "")
                                .toUpperCase()
                                .split(/[\s-]+/)
                                .filter((p) => p.length > 0);
                              
                              const prefix = nameParts.length > 0 
                                ? nameParts.slice(0, 3).map(p => p.substring(0, 4)).join("-")
                                : "SKU";
                                
                              const randomStr = Math.random().toString(36).substring(2, 6).toUpperCase();
                              setFormData({ ...formData, sku: `${prefix}-${randomStr}` });
                            }}
                          >
                            SKU Aleatório
                          </Button>
                        </div>
                      </div>
                      <div className="space-y-2">
                        <Input
                          label="Código de Barras"
                          name="barcode"
                          placeholder="Ex: 7890123456789 ou bipar..."
                          value={formData.barcode}
                          onChange={(e) => setFormData({ ...formData, barcode: e.target.value })}
                        />
                        <BarcodeGenerator 
                          productName={formData.name}
                          sku={formData.sku}
                          barcode={formData.barcode}
                          onGenerate={() => {
                            // simple ean-13 generation starting with country code ex 789 (brazil) + 9 random digits + checksum digit (ignored for simple generate here)
                            const base = "789" + Math.floor(Math.random() * 1000000000).toString().padStart(9, "0");
                            // EAN13 Checksum calc
                            let sum = 0;
                            for (let i = 0; i < 12; i++) { sum += parseInt(base[i]) * (i % 2 === 0 ? 1 : 3); }
                            const checkDigit = (10 - (sum % 10)) % 10;
                            setFormData({ ...formData, barcode: base + checkDigit });
                          }}
                        />
                      </div>
                    </div>
                    <div className="space-y-2">
                      <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                        Descrição
                      </label>
                      <RichTextEditor
                        value={formData.description}
                        onChange={(description) => setFormData({ ...formData, description })}
                        placeholder="Detalhes sobre o produto, aplicação, materiais..."
                      />
                    </div>
                  </div>
                </div>
              </div>
              </div>

              <CamposFiscaisDoProduto valor={dadosFiscais} aoMudar={setDadosFiscais} nomeDoProduto={formData.name} />

              <div className="rounded-[20px] border border-slate-200/60 bg-white shadow-[0_2px_14px_rgba(0,0,0,0.02)] overflow-hidden transition-all duration-300 hover:border-slate-300/80 hover:shadow-[0_8px_30px_rgba(0,0,0,0.06)]">
                <button
                  type="button"
                  onClick={() => setGeneralAccordionOpen((prev) => ({ ...prev, value: !prev.value }))}
                  className="w-full flex items-center justify-between gap-4 px-6 py-5 text-left bg-transparent transition-colors hover:bg-slate-50/50"
                >
                  <span className="flex items-center gap-3">
                    <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-slate-50 text-[var(--ks-color-primary-strong)] border border-slate-100 shadow-[0_2px_4px_rgba(0,0,0,0.02)]">
                      <DollarSign size={16} />
                    </span>
                    <span className="min-w-0">
                      <span className="block text-[15px] font-bold text-slate-800 tracking-tight">Valor</span>
                      <span className="block text-[13px] font-medium text-slate-500 mt-0.5">Preço, custo e análise de margem</span>
                    </span>
                  </span>
                  <ChevronDown
                    size={18}
                    className={`text-[var(--ks-color-text-soft)] transition-transform duration-200 ${generalAccordionOpen.value ? "rotate-180" : ""}`}
                  />
                </button>
                <div className={`grid transition-all duration-200 ease-out ${generalAccordionOpen.value ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"}`}>
                  <div className="overflow-hidden">
                    <div className="border-t border-[rgba(198,203,224,0.4)] p-5 space-y-5">
                    <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                      <div className="space-y-2">
                        <div className="flex items-center justify-between gap-3">
                          <div className="flex items-center gap-2">
                            <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                              Preço (R$)
                            </label>
                            <InfoTooltip text="Preço final de venda do produto." />
                          </div>
                          <div className="flex items-center gap-2">
                            <Switch
                              checked={formData.price_on_request}
                              disabled={formData.allowed_sale_qty_enabled || formData.use_variation_price_only}
                              onCheckedChange={(checked) =>
                                setFormData((p) => ({
                                  ...p,
                                  price_on_request: checked,
                                  use_variation_price_only: checked ? false : p.use_variation_price_only,
                                  price: checked ? "" : p.price,
                                }))
                              }
                            />
                            <span className="text-xs text-[var(--ks-color-text-muted)] select-none">
                              Sob consulta
                            </span>
                          </div>
                        </div>
                        <input
                          type="text"
                          inputMode="decimal"
                          required={!formData.price_on_request && !formData.allowed_sale_qty_enabled && !formData.use_variation_price_only}
                          disabled={formData.price_on_request || formData.allowed_sale_qty_enabled || formData.use_variation_price_only}
                          className="w-full px-4 py-2 rounded-full border border-[rgba(198,203,224,0.9)] text-sm outline-none bg-white focus:ring-2 focus:ring-[rgba(10, 192, 214,0.16)] focus:border-[rgba(10, 192, 214,0.9)] disabled:bg-[rgba(248,249,252,0.9)] disabled:text-[var(--ks-color-text-soft)] disabled:cursor-not-allowed"
                          value={formData.price}
                          onChange={(e) =>
                            setFormData({ ...formData, price: formatMoneyInput(e.target.value) })
                          }
                          placeholder="0,00"
                        />
                        {formData.allowed_sale_qty_enabled && (
                          <p className="text-[11px] text-[var(--ks-color-text-muted)]">
                            Com Intervalo de Quantidades ativo, o valor vem dos cards de quantidade.
                          </p>
                        )}
                        <div className="flex items-center gap-2">
                          <Switch
                            checked={formData.use_variation_price_only}
                            disabled={formData.allowed_sale_qty_enabled || formData.price_on_request}
                            onCheckedChange={(checked) =>
                              setFormData((prev) => ({
                                ...prev,
                                use_variation_price_only: checked,
                                price_on_request: checked ? false : prev.price_on_request,
                                price: checked ? "" : prev.price,
                              }))
                            }
                          />
                          <span className="text-xs text-[var(--ks-color-text-muted)] select-none">
                            Usar preço apenas das variações
                          </span>
                        </div>
                        {formData.use_variation_price_only && (
                          <p className="text-[11px] text-[var(--ks-color-text-muted)]">
                            O preço base é ignorado e o valor final será composto apenas pelas opções escolhidas.
                          </p>
                        )}

                        {/* Valor mínimo do item: lona, adesivo, chapa. Cada linha é
                            comparada sozinha com ele, depois de faixas e adicionais. */}
                        {vendidoPorMedida(formData.unit_type) && !formData.price_on_request && (
                          <div className="space-y-2 pt-2">
                            <div className="flex items-center gap-2">
                              <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                                Valor mínimo do item (R$)
                              </label>
                              <InfoTooltip
                                text={`Se a conta de um item der menos que este valor, o item custa este valor. Cada item é comparado sozinho: 20 adesivos na mesma linha contam juntos; itens diferentes não se somam. Deixe vazio para não usar.`}
                              />
                            </div>
                            <input
                              type="text"
                              inputMode="decimal"
                              className="w-full px-4 py-2 rounded-full border border-[rgba(198,203,224,0.9)] text-sm outline-none bg-white focus:ring-2 focus:ring-[rgba(10, 192, 214,0.16)] focus:border-[rgba(10, 192, 214,0.9)]"
                              value={formData.valor_minimo_item}
                              onChange={(e) =>
                                setFormData({ ...formData, valor_minimo_item: e.target.value.replace(/\D/g, "") ? formatMoneyInput(e.target.value) : "" })
                              }
                              placeholder="Sem mínimo"
                            />
                            {parseMoneyInput(formData.valor_minimo_item) > 0 ? (
                              <>
                                <p className="text-[11px] text-[var(--ks-color-text-muted)]">
                                  Um item de {nomeDaMedida(formData.unit_type)} pequeno custa pelo menos{" "}
                                  {parseMoneyInput(formData.valor_minimo_item).toLocaleString("pt-BR", { style: "currency", currency: "BRL" })}. Preço digitado
                                  à mão no orçamento não leva o mínimo; desconto e cupom vêm depois.
                                </p>
                                <div className="flex flex-wrap items-center gap-x-5 gap-y-2">
                                  {(
                                    [
                                      ["valor_minimo_orcamentos", "Vale nos orçamentos"],
                                      ["valor_minimo_loja", "Vale na loja"],
                                      ["valor_minimo_pdv", "Vale no PDV"],
                                    ] as const
                                  ).map(([chave, rotulo]) => (
                                    <div key={chave} className="flex items-center gap-2">
                                      <Switch
                                        checked={formData[chave]}
                                        onCheckedChange={(checked) => setFormData((prev) => ({ ...prev, [chave]: checked }))}
                                      />
                                      <span className="text-xs text-[var(--ks-color-text-muted)] select-none">{rotulo}</span>
                                    </div>
                                  ))}
                                </div>
                              </>
                            ) : null}
                          </div>
                        )}
                      </div>

                      {podeVerCustos && (
                      <div className="space-y-2">
                        <div className="flex items-center gap-2">
                          <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                            Custo Estimado (R$)
                          </label>
                          <InfoTooltip text="Valor estimado caso você não queira detalhar processos ou materiais. Ideal para precificação rápida." />
                        </div>
                        <input
                          type="text"
                          inputMode="decimal"
                          className="w-full px-4 py-2 rounded-full border border-[rgba(198,203,224,0.9)] text-sm outline-none bg-white focus:ring-2 focus:ring-[rgba(10, 192, 214,0.16)] focus:border-[rgba(10, 192, 214,0.9)]"
                          value={formData.estimated_base_cost}
                          onChange={(e) => {
                            const newVal = formatMoneyInput(e.target.value);
                            const numVal = parseMoneyInput(newVal);
                            setFormData({ ...formData, estimated_base_cost: newVal });
                            setCostBreakdown(prev => ({ ...prev, estimated: numVal }));
                            setCostTotal(custoDoProduto({
                              estimatedBaseCost: numVal,
                              somaDaFicha: costBreakdown.processes + costBreakdown.materials,
                              unitType: formData.unit_type,
                              referenceWidthM: refsDePrecificacao.w,
                              referenceHeightM: refsDePrecificacao.h,
                            }));
                          }}
                          placeholder="0,00"
                          disabled={!podeMexerNoCusto}
                        />
                      </div>
                      )}
                    </div>

                    {podeVerCustos && (
                    <PricingBlock
                      costTotal={costTotal}
                      variaveisPct={variaveisPct}
                      custoFixoUnitario={
                        taxaEstrutura > 0 && minutosFichaPorUnidade > 0
                          ? Math.round((minutosFichaPorUnidade / 60) * taxaEstrutura * 100) / 100
                          : 0
                      }
                      unidadeDeVenda={formData.unit_type}
                      price={parseMoneyInput(formData.price)}
                      onApplyPrice={(price) => setFormData(prev => ({ ...prev, price: formatMoneyInput(price.toFixed(2)) }))}
                      category={categories.find(c => c.id === formData.category_id)}
                    />
                    )}

                    <div className="rounded-2xl border border-[rgba(198,203,224,0.6)] bg-[var(--ks-color-bg-soft)] p-4 space-y-3">
                      <div className="flex items-center justify-between gap-3">
                        <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                          Quantidade Mínima de Venda
                        </label>
                        <Switch
                          checked={formData.min_sale_qty_enabled}
                          disabled={formData.allowed_sale_qty_enabled}
                          onCheckedChange={(checked) => {
                            setFormData((prev) => ({
                              ...prev,
                              min_sale_qty_enabled: checked,
                              min_sale_qty: checked ? prev.min_sale_qty : "",
                              allowed_sale_qty_enabled: checked ? false : prev.allowed_sale_qty_enabled,
                            }));
                            if (checked) {
                              setQuantityIntervals([]);
                              setNewIntervalQty("");
                              setNewIntervalPrice("");
                            }
                          }}
                        />
                      </div>
                      {formData.min_sale_qty_enabled ? (
                        <Input
                          label="Quantidade mínima"
                          type="text"
                          inputMode="decimal"
                          placeholder="Ex: 10"
                          value={formData.min_sale_qty}
                          onChange={(e) => setFormData((prev) => ({ ...prev, min_sale_qty: e.target.value }))}
                        />
                      ) : (
                        <p className="text-xs text-[var(--ks-color-text-muted)]">
                          Ative para exigir quantidade mínima na venda desse produto.
                        </p>
                      )}
                    </div>

                    <div className="rounded-2xl border border-[rgba(198,203,224,0.6)] bg-[var(--ks-color-bg-soft)] p-4 space-y-3">
                      <div className="flex items-center justify-between gap-3">
                        <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                          Ativar Intervalo de Quantidades
                        </label>
                        <Switch
                          checked={formData.allowed_sale_qty_enabled}
                          disabled={formData.min_sale_qty_enabled}
                          onCheckedChange={(checked) => {
                            setFormData((prev) => ({
                              ...prev,
                              allowed_sale_qty_enabled: checked,
                              min_sale_qty_enabled: checked ? false : prev.min_sale_qty_enabled,
                              min_sale_qty: checked ? "" : prev.min_sale_qty,
                              price_on_request: checked ? false : prev.price_on_request,
                              use_variation_price_only: checked ? false : prev.use_variation_price_only,
                            }));
                            if (!checked) {
                              setQuantityIntervals([]);
                              setNewIntervalQty("");
                              setNewIntervalPrice("");
                              setErroDoIntervalo(null);
                            }
                          }}
                        />
                      </div>

                      {formData.allowed_sale_qty_enabled ? (
                        <>
                          <div className="grid grid-cols-1 gap-3 md:grid-cols-[1fr_1fr_auto]">
                            <Input
                              label="Quantidade"
                              type="text"
                              inputMode="decimal"
                              placeholder="Ex: 250"
                              value={newIntervalQty}
                              onChange={(e) => setNewIntervalQty(e.target.value)}
                            />
                            <Input
                              label="Valor da quantidade"
                              type="text"
                              inputMode="decimal"
                              placeholder="Ex: 100,00"
                              value={newIntervalPrice}
                              onChange={(e) => setNewIntervalPrice(formatMoneyInput(e.target.value))}
                            />
                            <div className="flex items-end">
                              <Button
                                type="button"
                                variant="outline"
                                icon={<Plus size={14} />}
                                onClick={addQuantityInterval}
                              >
                                Adicionar
                              </Button>
                            </div>
                          </div>

                          {erroDoIntervalo ? (
                            <p role="alert" className="text-xs font-medium text-rose-600">
                              {erroDoIntervalo}
                            </p>
                          ) : null}

                          {quantityIntervals.length === 0 ? (
                            <div className="rounded-xl border border-dashed border-[var(--ks-color-border-subtle)] bg-white px-4 py-3 text-sm text-[var(--ks-color-text-muted)]">
                              Adicione os cards com quantidade e valor total (ex.: 250 - R$ 100,00).
                            </div>
                          ) : (
                            <div className="grid grid-cols-1 gap-2 md:grid-cols-2">
                              {quantityIntervals.map((interval) => (
                                <div
                                  key={interval.id}
                                  className="rounded-xl border border-[var(--ks-color-border-subtle)] bg-white px-3 py-2.5 shadow-[0_8px_20px_-18px_rgba(17,24,39,0.45)]"
                                >
                                  <div className="grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto] items-end gap-2 min-w-0">
                                    <div className="min-w-0">
                                      <p className="text-[10px] uppercase tracking-[0.14em] text-[var(--ks-color-text-soft)]">
                                        Quantidade
                                      </p>
                                      {editingIntervalId === interval.id ? (
                                        <input
                                          type="text"
                                          inputMode="decimal"
                                          value={editingIntervalQty}
                                          onChange={(e) => setEditingIntervalQty(e.target.value)}
                                          placeholder="Ex: 250"
                                          className="w-full rounded-md border border-[var(--ks-color-border-subtle)] bg-white px-2 py-1 text-sm font-semibold text-[var(--ks-color-text-primary)] outline-none transition-all focus:ring-2 focus:ring-[rgba(10,192,214,0.16)] focus:border-[rgba(10,192,214,0.9)]"
                                        />
                                      ) : (
                                        <p className="text-sm font-semibold text-[var(--ks-color-text-primary)] leading-6">
                                          {interval.quantity || "--"}
                                        </p>
                                      )}
                                    </div>
                                    <div className="min-w-0 text-right">
                                      <p className="text-[10px] uppercase tracking-[0.14em] text-[var(--ks-color-text-soft)]">
                                        Valor
                                      </p>
                                      {editingIntervalId === interval.id ? (
                                        <input
                                          type="text"
                                          inputMode="decimal"
                                          value={editingIntervalPrice}
                                          onChange={(e) => setEditingIntervalPrice(formatMoneyInput(e.target.value))}
                                          placeholder="Ex: 100,00"
                                          className="w-full rounded-md border border-[var(--ks-color-border-subtle)] bg-white px-2 py-1 text-sm font-semibold text-[var(--ks-color-text-primary)] outline-none transition-all focus:ring-2 focus:ring-[rgba(10,192,214,0.16)] focus:border-[rgba(10,192,214,0.9)]"
                                        />
                                      ) : (
                                        <p className="text-sm font-semibold text-[var(--ks-color-text-primary)] leading-6">
                                          {interval.price ? `R$ ${interval.price}` : "--"}
                                        </p>
                                      )}
                                    </div>
                                    <div className="flex items-center gap-1">
                                    {editingIntervalId === interval.id ? (
                                      <button
                                        type="button"
                                        onClick={() => saveEditQuantityInterval(interval.id)}
                                        className="inline-flex h-7 w-7 items-center justify-center rounded-full border border-emerald-200 text-emerald-600 transition-colors hover:bg-emerald-50"
                                        aria-label="Salvar intervalo"
                                      >
                                        <Check size={12} />
                                      </button>
                                    ) : (
                                      <button
                                        type="button"
                                        onClick={() => startEditQuantityInterval(interval)}
                                        className="inline-flex h-7 w-7 items-center justify-center rounded-full border border-[var(--ks-color-border-subtle)] text-[var(--ks-color-text-soft)] transition-colors hover:border-[rgba(10,192,214,0.35)] hover:bg-[rgba(10,192,214,0.06)] hover:text-[var(--ks-color-primary)]"
                                        aria-label="Editar intervalo"
                                      >
                                        <Pencil size={12} />
                                      </button>
                                    )}
                                    <button
                                      type="button"
                                      onClick={() => removeQuantityInterval(interval.id)}
                                      className="inline-flex h-7 w-7 items-center justify-center rounded-full 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"
                                      aria-label="Remover intervalo"
                                    >
                                      <Trash2 size={12} />
                                    </button>
                                  </div>
                                </div>
                                </div>
                              ))}
                            </div>
                          )}
                        </>
                      ) : (
                        <p className="text-xs text-[var(--ks-color-text-muted)]">
                          Ative para vender esse produto apenas nas quantidades cadastradas.
                        </p>
                      )}
                    </div>

                    <div className="rounded-lg border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-surface-secondary)] p-4">
                      <div className="flex items-center justify-between text-sm">
                        <span className="text-[var(--ks-color-text-muted)]">Custo total</span>
                        <span className="font-medium">{formatMoney(costTotal)}</span>
                      </div>
                    </div>
                    </div>
                  </div>
                </div>
              </div>

              {noEstoqueV2 ? (
                /* Estoque novo: o controle mora na aba Estoque. Aqui só o atalho. */
                <button
                  type="button"
                  onClick={() => setAbaAtual("estoque")}
                  className="flex w-full items-center justify-between gap-4 rounded-[20px] border border-slate-200/60 bg-white px-6 py-5 text-left shadow-[0_2px_14px_rgba(0,0,0,0.02)] transition-all duration-300 hover:border-slate-300/80 hover:shadow-[0_8px_30px_rgba(0,0,0,0.06)]"
                >
                  <span className="flex items-center gap-3">
                    <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] border border-slate-100 bg-slate-50 text-[var(--ks-color-primary-strong)] shadow-[0_2px_4px_rgba(0,0,0,0.02)]">
                      <Package size={16} />
                    </span>
                    <span className="min-w-0">
                      <span className="block text-[15px] font-bold tracking-tight text-slate-800">Estoque</span>
                      <span className="mt-0.5 block text-[13px] font-medium text-slate-500">De onde sai quando vende, saldo e prévia: na aba Estoque</span>
                    </span>
                  </span>
                  <span className="text-xs font-semibold text-[var(--ks-color-primary)]">Abrir</span>
                </button>
              ) : null}
              {!noEstoqueV2 ? (
              <div className="rounded-[20px] border border-slate-200/60 bg-white shadow-[0_2px_14px_rgba(0,0,0,0.02)] overflow-hidden transition-all duration-300 hover:border-slate-300/80 hover:shadow-[0_8px_30px_rgba(0,0,0,0.06)]">
                <button
                  type="button"
                  onClick={() => setGeneralAccordionOpen((prev) => ({ ...prev, stock: !prev.stock }))}
                  className="w-full flex items-center justify-between gap-4 px-6 py-5 text-left bg-transparent transition-colors hover:bg-slate-50/50"
                >
                  <span className="flex items-center gap-3">
                    <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-slate-50 text-[var(--ks-color-primary-strong)] border border-slate-100 shadow-[0_2px_4px_rgba(0,0,0,0.02)]">
                      <Package size={16} />
                    </span>
                    <span className="min-w-0">
                      <span className="block text-[15px] font-bold text-slate-800 tracking-tight">Estoque</span>
                      <span className="block text-[13px] font-medium text-slate-500 mt-0.5">Controle, regras e saldo do produto</span>
                    </span>
                  </span>
                  <ChevronDown
                    size={18}
                    className={`text-[var(--ks-color-text-soft)] transition-transform duration-200 ${generalAccordionOpen.stock ? "rotate-180" : ""}`}
                  />
                </button>
                <div className={`grid transition-all duration-200 ease-out ${generalAccordionOpen.stock ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"}`}>
                  <div className="overflow-hidden">
                    <div className="border-t border-[rgba(198,203,224,0.4)] p-5 space-y-4">
                    <div className="flex items-center justify-between rounded-xl border border-[var(--ks-color-border-subtle)] bg-white px-3 py-2">
                      <div>
                        <p className="text-xs font-medium text-[var(--ks-color-text-primary)]">
                          Controlar estoque
                        </p>
                        <p className="text-[11px] text-[var(--ks-color-text-muted)]">
                          Ligado: a venda baixa o produto pronto (e os insumos da ficha deixam de baixar — eles se consomem na produção do lote). Desligado: nada de produto pronto baixa; insumos controlados da ficha continuam baixando na venda.
                        </p>
                      </div>
                      <Switch
                        checked={formData.track_inventory}
                        onCheckedChange={(checked) =>
                          setFormData((prev) => ({ ...prev, track_inventory: checked }))
                        }
                      />
                    </div>
                    <div className="flex items-center justify-between">
                      <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                        Estoque
                      </label>
                      <button
                        type="button"
                        onClick={() => formData.track_inventory && setIsInventoryModalOpen(true)}
                        disabled={!formData.track_inventory}
                        className="text-xs text-[var(--ks-color-primary)] hover:underline flex items-center gap-1 disabled:opacity-50 disabled:no-underline"
                      >
                        <History size={12} />
                        Ver histórico
                      </button>
                    </div>
                    <Input
                      type="text"
                      inputMode="decimal"
                      placeholder="0"
                      value={formData.stock}
                      onChange={(e) => setFormData({ ...formData, stock: e.target.value })}
                      required
                      readOnly
                      disabled={!formData.track_inventory}
                      className="bg-gray-50 text-gray-500 cursor-pointer disabled:cursor-not-allowed"
                      onClick={() => formData.track_inventory && setIsInventoryModalOpen(true)}
                    />
                    <p className="text-[10px] text-[var(--ks-color-text-muted)]">
                      {!formData.track_inventory
                        ? "Controle desativado para este produto."
                        : formData.inventory_scope === "option"
                          ? "É a soma dos saldos por opção, calculada sozinha. Ajuste pelas opções ou pelo histórico."
                          : formData.inventory_scope === "variant"
                            ? "É a soma dos saldos por combinação, calculada sozinha. Ajuste pela grade ou pelo histórico."
                            : "O estoque vive do histórico de movimentos. Clique para ajustar."}
                    </p>
                    <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                      Regra de estoque
                    </label>
                    <select
                      value={formData.inventory_scope}
                      disabled={!formData.track_inventory}
                      onChange={(event) =>
                        setFormData((prev) => ({
                          ...prev,
                          inventory_scope: event.target.value as "product" | "option" | "variant",
                          inventory_attribute_name:
                            event.target.value === "option" ? prev.inventory_attribute_name : "",
                        }))
                      }
                      className="h-10 w-full rounded-xl border border-[var(--ks-color-border-subtle)] bg-white px-3 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--ks-color-primary)]"
                    >
                      <option value="product">Por produto</option>
                      <option value="option">Por opção de atributo</option>
                      <option value="variant">Por combinação</option>
                    </select>
                    {formData.track_inventory && formData.inventory_scope === "option" && (
                      <select
                        value={formData.inventory_attribute_name}
                        disabled={!formData.track_inventory}
                        onChange={(event) =>
                          setFormData((prev) => ({ ...prev, inventory_attribute_name: event.target.value }))
                        }
                        className="h-10 w-full rounded-xl border border-[var(--ks-color-border-subtle)] bg-white px-3 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--ks-color-primary)]"
                      >
                        <option value="">Selecione o atributo que controla estoque</option>
                        {attributes.map((attribute) => (
                          <option key={attribute.id || attribute.name} value={attribute.name}>
                            {attribute.name}
                          </option>
                        ))}
                      </select>
                    )}
                    <p className="text-[10px] text-[var(--ks-color-text-muted)]">
                      Por opção permite controlar estoque por cor, tamanho ou outro atributo.
                    </p>
                    <div className="flex items-center justify-between rounded-xl border border-[var(--ks-color-border-subtle)] bg-white px-3 py-2">
                      <div>
                        <p className="text-xs font-medium text-[var(--ks-color-text-primary)]">
                          Permitir estoque negativo
                        </p>
                        <p className="text-[11px] text-[var(--ks-color-text-muted)]">
                          Ligado, a venda sem saldo entra mesmo assim e o estoque fica negativo. Desligado, a venda é bloqueada quando não há saldo.
                        </p>
                      </div>
                      <Switch
                        checked={formData.allow_negative_stock}
                        disabled={!formData.track_inventory}
                        onCheckedChange={(checked) =>
                          setFormData((prev) => ({ ...prev, allow_negative_stock: checked }))
                        }
                      />
                    </div>
                  </div>
                </div>
              </div>
            </div>
              ) : null}
            </div>

          <div className="space-y-4">
            <div className="rounded-[20px] border border-slate-200/60 bg-white shadow-[0_2px_14px_rgba(0,0,0,0.02)] overflow-hidden transition-all duration-300 hover:border-slate-300/80 hover:shadow-[0_8px_30px_rgba(0,0,0,0.06)]">
              <div className="w-full flex items-center justify-between gap-4 px-6 py-5 border-b border-slate-100 bg-transparent">
                <span className="flex items-center gap-3">
                  <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-slate-50 text-[var(--ks-color-primary-strong)] border border-slate-100 shadow-[0_2px_4px_rgba(0,0,0,0.02)]">
                    <Images size={16} />
                  </span>
                  <span className="min-w-0">
                    <span className="block text-[15px] font-bold text-slate-800 tracking-tight">Galeria de imagens</span>
                    <span className="block text-[13px] font-medium text-slate-500 mt-0.5">A imagem principal aparece nos cards e no destaque</span>
                  </span>
                </span>
              </div>
              <div className="p-5">
                <ProductImageGalleryEditor
                  images={productImages}
                  onChange={handleProductImagesChange}
                />
              </div>
            </div>

            <div className="rounded-[20px] border border-slate-200/60 bg-white shadow-[0_2px_14px_rgba(0,0,0,0.02)] overflow-hidden transition-all duration-300 hover:border-slate-300/80 hover:shadow-[0_8px_30px_rgba(0,0,0,0.06)]">
              <div className="w-full flex items-center justify-between gap-4 px-6 py-5 border-b border-slate-100 bg-transparent">
                <span className="flex items-center gap-3">
                  <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-slate-50 text-[var(--ks-color-primary-strong)] border border-slate-100 shadow-[0_2px_4px_rgba(0,0,0,0.02)]">
                    <Clapperboard size={16} />
                  </span>
                  <span className="min-w-0">
                    <span className="block text-[15px] font-bold text-slate-800 tracking-tight">Vídeo do produto</span>
                    <span className="block text-[13px] font-medium text-slate-500 mt-0.5">Aparece como o primeiro item da galeria na loja</span>
                  </span>
                </span>
              </div>
              <div className="p-5">
                <VideoDoProdutoEditor produtoId={productId ?? ""} valor={videoDoProduto} aoMudar={setVideoDoProduto} />
              </div>
            </div>

            <div className="rounded-[20px] border border-slate-200/60 bg-white shadow-[0_2px_14px_rgba(0,0,0,0.02)] overflow-hidden transition-all duration-300 hover:border-slate-300/80 hover:shadow-[0_8px_30px_rgba(0,0,0,0.06)]">
              <div className="w-full flex items-center justify-between gap-4 px-6 py-5 border-b border-slate-100 bg-transparent">
                <span className="flex items-center gap-3">
                  <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-slate-50 text-[var(--ks-color-primary-strong)] border border-slate-100 shadow-[0_2px_4px_rgba(0,0,0,0.02)]">
                    <Store size={16} />
                  </span>
                  <span className="min-w-0">
                    <span className="block text-[15px] font-bold text-slate-800 tracking-tight">Aparência no catálogo</span>
                    <span className="block text-[13px] font-medium text-slate-500 mt-0.5">Configure a visibilidade do produto online</span>
                  </span>
                </span>
              </div>
              <div className="p-5 space-y-6">
                <div className="flex items-center justify-between gap-3 rounded-xl border border-[var(--ks-color-border-subtle)] bg-white px-4 py-3">
                  <div className="space-y-1">
                    <p className="text-xs font-semibold text-[var(--ks-color-text-primary)]">
                      Exibir na vitrine
                    </p>
                    <p className="text-[11px] text-[var(--ks-color-text-muted)]">
                      Defina se o produto aparece no catálogo online.
                    </p>
                  </div>
                  <Switch
                    checked={formData.show_in_catalog}
                    onCheckedChange={(checked) =>
                      setFormData({
                        ...formData,
                        show_in_catalog: checked,
                      })
                    }
                  />
                </div>
              </div>
            </div>
            <InventoryHistoryModal
              productId={productId || ""}
              productName={formData.name}
              currentStock={Number(formData.stock) || 0}
              open={isInventoryModalOpen}
              onOpenChange={setIsInventoryModalOpen}
              onStockUpdate={(newStock) => setFormData(prev => ({ ...prev, stock: String(newStock) }))}
              onOptionStockUpdate={handleOptionStockUpdate}
              onVariationStockUpdate={handleVariationStockUpdate}
            />
          </div>
               </div>
             </TabsContent>

             <TabsContent value="composition">
               {productId && (
                 <ProductComposition
                   productId={productId}
                   onUpdateCost={() => fetchProduct(productId)}
                   estoqueNovo={noEstoqueV2}
                 />
               )}
             </TabsContent>

             {noEstoqueV2 && productId ? (
               <TabsContent value="estoque">
                 <EstoqueDoProduto
                   produtoId={productId}
                   aoMudarModo={(modo) =>
                     /* O banco liga track_inventory = (modo pronto); o formulário acompanha
                        para a tela não mostrar o número velho. */
                     setFormData((prev) => ({ ...prev, track_inventory: modo === "pronto" }))
                   }
                 />
               </TabsContent>
             ) : null}

             <TabsContent value="variations">
                <ProductVariations
                  attributes={attributes}
                  setAttributes={setAttributes}
                  productImages={productImages}
                  variations={variations}
                  setVariations={setVariations}
                  basePrice={parseMoneyInput(formData.price)}
                  baseCost={costTotal}
                  inventoryScope={!noEstoqueV2 && formData.track_inventory ? formData.inventory_scope : "product"}
                  unitType={formData.unit_type}
                  estoqueNovo={noEstoqueV2}
                />
             </TabsContent>

             <TabsContent value="custom-fields">
               <ProductCustomFields
                 customFields={customFields}
                 setCustomFields={setCustomFields}
                 variations={variations}
                 attributes={attributes}
               />
             </TabsContent>

             <TabsContent value="tiers">
               <ProductPriceTiers
                 tiers={formData.allowed_sale_qty_enabled ? intervalPricingPreview.tiers : priceTiers}
                 onChange={formData.allowed_sale_qty_enabled ? () => undefined : setPriceTiers}
                 basePrice={parseMoneyInput(formData.price)}
                 costTotal={costTotal}
                 priceOnRequest={formData.price_on_request}
                 readOnly={formData.allowed_sale_qty_enabled}
                 readOnlyHint="Com Intervalo de Quantidades ativo, as faixas são geradas automaticamente pelos cards de quantidade + valor."
                 unitType={formData.unit_type}
                 category={categories.find((c) => c.id === formData.category_id)}
                 saleQuantityLimits={{
                   min_sale_qty_enabled: formData.min_sale_qty_enabled,
                   min_sale_qty: formData.min_sale_qty_enabled ? parseMinSaleQtyInput(formData.min_sale_qty) : null,
                   max_sale_qty_enabled: false,
                   max_sale_qty: null,
                   allowed_sale_qty_enabled: formData.allowed_sale_qty_enabled,
                   allowed_sale_quantities: formData.allowed_sale_qty_enabled
                     ? intervalPricingPreview.allowedQuantities
                     : null,
                 }}
               />
             </TabsContent>

             <TabsContent value="combos">
               {productId && <ProductCombos productId={productId} />}
             </TabsContent>

             <TabsContent value="logistics">
              <div className="max-w-3xl space-y-4">
                <div className="rounded-[20px] border border-slate-200/60 bg-white p-6 shadow-[0_2px_14px_rgba(0,0,0,0.02)]">
                  <div className="flex items-start gap-3">
                    <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] border border-slate-100 bg-slate-50 text-[var(--ks-color-primary-strong)]">
                      <Weight size={16} />
                    </span>
                    <div className="min-w-0">
                      <h3 className="text-[15px] font-bold tracking-tight text-slate-800">Peso do produto</h3>
                      <p className="mt-0.5 text-[13px] font-medium text-slate-500">
                        Peso da unidade já embalada, usado como base na cotação.
                      </p>
                    </div>
                  </div>

                  <div className="mt-5 max-w-[220px]">
                    <Input
                      label="Peso (kg)"
                      inputMode="decimal"
                      placeholder="Ex: 0,450"
                      value={formData.shipping_weight_kg}
                      onChange={(e) => setFormData({ ...formData, shipping_weight_kg: e.target.value })}
                    />
                  </div>
                </div>

                <div className="rounded-[20px] border border-slate-200/60 bg-white p-6 shadow-[0_2px_14px_rgba(0,0,0,0.02)]">
                  <div className="flex items-start gap-3">
                    <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] border border-slate-100 bg-slate-50 text-[var(--ks-color-primary-strong)]">
                      <Ruler size={16} />
                    </span>
                    <div className="min-w-0">
                      <h3 className="text-[15px] font-bold tracking-tight text-slate-800">Dimensões da embalagem</h3>
                      <p className="mt-0.5 text-[13px] font-medium text-slate-500">
                        Medidas da caixa fechada, não do produto solto.
                      </p>
                    </div>
                  </div>

                  {/*
                    Sem `description` por campo: o texto de apoio ficava entre o
                    rotulo e o input e, tendo 1 ou 2 linhas conforme o campo,
                    empurrava cada input para uma altura diferente. Um unico
                    texto acima do grupo alinha tudo e diz o mesmo.
                  */}
                  <div className="mt-5 grid grid-cols-1 gap-4 sm:grid-cols-3">
                    <Input
                      label="Largura (cm)"
                      inputMode="decimal"
                      placeholder="Ex: 20"
                      value={formData.shipping_width_cm}
                      onChange={(e) => setFormData({ ...formData, shipping_width_cm: e.target.value })}
                    />
                    <Input
                      label="Altura (cm)"
                      inputMode="decimal"
                      placeholder="Ex: 5"
                      value={formData.shipping_height_cm}
                      onChange={(e) => setFormData({ ...formData, shipping_height_cm: e.target.value })}
                    />
                    <Input
                      label="Comprimento (cm)"
                      inputMode="decimal"
                      placeholder="Ex: 30"
                      value={formData.shipping_length_cm}
                      onChange={(e) => setFormData({ ...formData, shipping_length_cm: e.target.value })}
                    />
                  </div>
                </div>

                <p className="px-1 text-[13px] text-slate-500">
                  O catálogo público usa esses valores para calcular o frete automaticamente. Sem eles, a
                  cotação não aparece para o cliente.
                </p>
              </div>
            </TabsContent>

             <TabsContent value="production">
               <div className="grid grid-cols-1 gap-6">
                 <div className="rounded-[20px] border border-slate-200/60 bg-white shadow-[0_2px_14px_rgba(0,0,0,0.02)] overflow-hidden">
                   <div className="flex items-center gap-3 border-b border-slate-100 px-6 py-5">
                     <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-slate-50 text-[var(--ks-color-primary-strong)] border border-slate-100">
                       <Clock3 size={16} />
                     </span>
                     <div className="min-w-0">
                       <p className="text-[15px] font-bold tracking-tight text-slate-800">Prazo de produção</p>
                       <p className="text-[13px] font-medium text-slate-500">
                         Informe quanto tempo esse produto leva para ficar pronto.
                       </p>
                     </div>
                   </div>
                   <div className="space-y-5 p-5">
                     <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
                       <Input
                         label="Tempo de produção"
                         type="text"
                         inputMode="decimal"
                         placeholder="Ex: 5"
                         value={formData.production_time_value}
                         onChange={(e) =>
                           setFormData((prev) => ({ ...prev, production_time_value: e.target.value }))
                         }
                       />
                       <div className="space-y-2">
                         <label className="text-xs font-medium text-[var(--ks-color-text-soft)] uppercase tracking-[0.16em]">
                           Unidade
                         </label>
                         <CustomSelect
                           options={[
                             { value: "hours", label: "Horas" },
                             { value: "days", label: "Dias corridos" },
                             { value: "business_days", label: "Dias úteis" },
                             { value: "weeks", label: "Semanas" },
                           ]}
                           value={formData.production_time_unit}
                           onChange={(value) =>
                             setFormData((prev) => ({ ...prev, production_time_unit: value || "business_days" }))
                           }
                         />
                       </div>
                     </div>

                     <div className="border-t border-dashed border-[var(--ks-color-border-subtle)] pt-4">
                       <div className="flex items-start gap-3">
                         <span className="mt-0.5 inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[rgba(10,192,214,0.10)] text-[var(--ks-color-primary)]">
                           <Clock3 size={18} />
                         </span>
                         <div className="min-w-0">
                           <p className="text-sm font-semibold text-[var(--ks-color-text-primary)]">
                             Como o prazo aparece no catálogo
                           </p>
                           <p className="mt-1 text-[15px] font-semibold tracking-[-0.02em] text-[var(--ks-color-primary)]">
                            {formData.production_time_value.trim()
                              ? formatProductionLeadTime(
                                  parseMinSaleQtyInput(formData.production_time_value),
                                  formData.production_time_unit as "days" | "hours" | "business_days" | "weeks" | null
                                ) || "Prazo não configurado"
                              : "Prazo não configurado"}
                           </p>
                           <p className="mt-1 text-xs text-[var(--ks-color-text-muted)]">
                             {formData.production_time_value.trim()
                               ? "Esse texto aparece direto na página do produto, ao lado do ícone de relógio."
                               : "Se deixar em branco, o prazo não será exibido na página pública do produto."}
                           </p>
                         </div>
                       </div>
                     </div>
                   </div>
                 </div>

                 <div className="rounded-[20px] border border-slate-200/60 bg-white shadow-[0_2px_14px_rgba(0,0,0,0.02)] overflow-hidden">
                   <div className="flex items-center gap-3 border-b border-slate-100 px-6 py-5">
                     <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-slate-50 text-[var(--ks-color-primary-strong)] border border-slate-100">
                       <FileText size={16} />
                     </span>
                     <div className="min-w-0">
                       <p className="text-[15px] font-bold tracking-tight text-slate-800">Gabarito para download</p>
                       <p className="text-[13px] font-medium text-slate-500">
                         Envie o arquivo técnico para o cliente baixar na página do produto.
                       </p>
                     </div>
                   </div>
                   <div className="space-y-5 p-5">
                     <div className="grid grid-cols-1 gap-4 lg:grid-cols-2 2xl:grid-cols-4">
                       <ProductProductionFileUpload
                         format="ai"
                         title="Gabarito Illustrator"
                         value={findProductionTemplate(formData.production_templates, "ai")}
                         onChange={(value) =>
                           setFormData((prev) => ({
                             ...prev,
                             production_templates: upsertProductionTemplate(
                               prev.production_templates,
                               value ? { ...value, format: "ai" } : null,
                               "ai"
                             ),
                           }))
                         }
                       />
                       <ProductProductionFileUpload
                         format="cdr"
                         title="Gabarito CorelDRAW"
                         value={findProductionTemplate(formData.production_templates, "cdr")}
                         onChange={(value) =>
                           setFormData((prev) => ({
                             ...prev,
                             production_templates: upsertProductionTemplate(
                               prev.production_templates,
                               value ? { ...value, format: "cdr" } : null,
                               "cdr"
                             ),
                           }))
                         }
                       />
                       <ProductProductionFileUpload
                         format="pdf"
                         title="Gabarito PDF"
                         value={findProductionTemplate(formData.production_templates, "pdf")}
                         onChange={(value) =>
                           setFormData((prev) => ({
                             ...prev,
                             production_templates: upsertProductionTemplate(
                               prev.production_templates,
                               value ? { ...value, format: "pdf" } : null,
                               "pdf"
                             ),
                           }))
                         }
                       />
                       <div className="flex h-full flex-col rounded-xl border border-slate-200 bg-white p-3 shadow-sm">
                         <div className="flex items-center gap-2.5">
                           <Image src="/icons/templates/canva.svg" alt="Canva" width={24} height={24} className="h-6 w-6 shrink-0 object-contain" />
                           <div className="min-w-0">
                             <p className="truncate text-sm font-semibold text-slate-900">Link do Canva</p>
                           </div>
                         </div>

                         <div className="mt-3 flex flex-1 flex-col">
                           <Input
                             placeholder="https://www.canva.com/..."
                             icon={<Link2 size={14} />}
                             className="text-sm"
                             value={findProductionTemplate(formData.production_templates, "canva")?.url || ""}
                             onChange={(event) => {
                               const nextUrl = event.target.value;
                               setFormData((prev) => {
                                 const current = findProductionTemplate(prev.production_templates, "canva");
                                 return {
                                   ...prev,
                                   production_templates: upsertProductionTemplate(
                                     prev.production_templates,
                                     nextUrl.trim()
                                       ? {
                                           format: "canva",
                                           url: nextUrl,
                                           name: current?.name || "Canva",
                                         }
                                       : null,
                                     "canva"
                                   ),
                                 };
                               });
                             }}
                           />
                           <div className="mt-3 flex flex-wrap gap-2">
                             <Button
                               type="button"
                               size="sm"
                               variant="outline"
                               disabled={!findProductionTemplate(formData.production_templates, "canva")?.url}
                               onClick={() => {
                                 const canvaUrl = findProductionTemplate(formData.production_templates, "canva")?.url;
                                 if (canvaUrl) window.open(canvaUrl, "_blank", "noopener,noreferrer");
                               }}
                               icon={<ExternalLink size={14} />}
                               className="rounded-lg"
                             >
                               Abrir
                             </Button>
                             <Button
                               type="button"
                               size="sm"
                               variant="ghost"
                               disabled={!findProductionTemplate(formData.production_templates, "canva")?.url}
                               onClick={() =>
                                 setFormData((prev) => ({
                                   ...prev,
                                   production_templates: upsertProductionTemplate(prev.production_templates, null, "canva"),
                                 }))
                               }
                               icon={<Trash2 size={14} />}
                               className="rounded-lg"
                             >
                               Limpar
                             </Button>
                           </div>
                           {!findProductionTemplate(formData.production_templates, "canva")?.url ? (
                             <div className="mt-3 flex flex-1 items-center">
                               <div className="w-full rounded-xl border border-dashed border-slate-200 bg-slate-50/70 px-3 py-4 text-center">
                                 <p className="text-xs font-medium text-slate-500">Sem link</p>
                               </div>
                             </div>
                           ) : null}
                         </div>
                       </div>
                     </div>
                   </div>
                 </div>

                 <ProductOptionalServices
                   grupos={gruposDeServico}
                   servicos={servicosDaLoja}
                   custos={custosDeServico}
                   vinculos={vinculosDeServico}
                   onVinculos={setVinculosDeServico}
                   onBiblioteca={({ grupos, servicos, custos }) => {
                     setGruposDeServico(grupos);
                     setServicosDaLoja(servicos);
                     setCustosDeServico(custos);
                   }}
                   carregando={carregandoServicos}
                 />
               </div>
             </TabsContent>
           </Tabs>
        </form>
      </div>
      <CategoryFormModal
        open={isCategoryModalOpen}
        onClose={() => setIsCategoryModalOpen(false)}
        categories={categories}
        onSaved={(category) => {
          if (!category?.id) return;
          setCategories((prev) =>
            [...prev, { id: category.id, name: category.name, pricing_rule: category.pricing_rule }]
              .sort((a, b) => a.name.localeCompare(b.name))
          );
          setFormData((prev) => ({ ...prev, category_id: category.id }));
        }}
      />
    </div>
  );
}
