"use client";

import { ChangeEvent, useEffect, useMemo, useState, useRef } from "react";
import { getSupabaseClient } from "@/lib/supabase";
import { getCompanyContext } from "@/lib/company-context";
import { Plus, Search, Edit, Trash2, Package, FileUp, Loader2, AlertTriangle, Check, Filter, LayoutGrid, List, CheckSquare, Copy, Eye, ChevronDown, RotateCcw } from "lucide-react";
import Link from "next/link";
import Image from "next/image";
import { miniatura } from "@/lib/foto";
import { AnimatePresence, motion } from "framer-motion";
import { PageHeader } from "@/components/ui/page-header";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { usePermissoes } from "@/lib/permissoes-do-usuario";
import { Checkbox } from "@/components/ui/checkbox";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { toast } from "sonner";
import * as XLSX from "xlsx";
import { CustomSelect } from "@/components/ui/custom-select";
import { ProductPreviewModal } from "./product-preview-modal";
import Barcode from "react-barcode";
import { useEstoqueV2 } from "@/lib/estoque/use-estoque-v2";
import { EstoqueNaLista, useEstoqueDaLista } from "@/components/estoque/estoque-na-lista";

interface Product {
  id: string;
  name: string;
  price: number;
  stock: number;
  active: boolean;
  image_url?: string;
  description?: string | null;
  category_id?: string | null;
  catalog_color?: string | null;
  show_in_catalog?: boolean | null;
  sku?: string | null;
  barcode?: string | null;
}

type ImportOptionValue = { name: string; value: string };

type ImportPreview = {
  rows: ProductImportRow[];
  headers: string[];
  normalizedHeaders: string[];
  columnMapping: Partial<Record<StandardProductField, number>>;
};

type ImportResult = {
  productsCreated: number;
  variantsCreated: number;
  categoriesCreated: number;
  imagesCreated: number;
  skippedRows: number;
  errors: { rowNumber: number; message: string }[];
  createdProductIds?: string[];
};

const unitTypeValues = new Set([
  "unit",
  "meter",
  "linear_meter",
  "square_meter",
  "box",
  "ream",
]);

type StandardProductField = "nome" | "preco" | "estoque" | "ativo" | "descricao" | "categoria" | "sku";

type DetectedAttributeColumn = {
  index: number;
  key: string;
};

const standardFieldLabels: Record<StandardProductField, string> = {
  nome: "Nome",
  preco: "Preço",
  estoque: "Estoque",
  ativo: "Ativo",
  descricao: "Descrição",
  categoria: "Categoria",
  sku: "SKU",
};

const standardFieldAliases: Record<Exclude<StandardProductField, "nome">, string[]> = {
  preco: ["preco", "preço", "valor", "price", "vlr", "valor venda"],
  estoque: [
    "estoque",
    "qtd estoque",
    "quantidade estoque",
    "qtde",
    "qtde estoque",
    "quantidade",
    "qtd",
    "saldo",
    "saldo estoque",
    "disponivel",
    "disponível",
    "em estoque",
    "stock",
    "stock qty",
    "stock quantity",
    "in stock",
    "inventory",
    "inventory qty",
    "inventory quantity",
    "on hand",
    "available",
  ],
  ativo: ["ativo", "status", "habilitado", "enabled"],
  descricao: ["descricao", "descrição", "details", "description"],
  categoria: ["categoria", "category", "grupo"],
  sku: ["sku", "codigo", "código", "ref", "referencia"],
};

const namePrimaryAliases = ["nome", "produto", "titulo", "title", "product name"];
const nameFallbackAliases = ["descricao", "descrição"];

const technicalFieldAliases = {
  images: ["imagens", "imagem", "image", "images", "image url", "image urls", "imagem url", "imagem urls"],
  pricePromotional: ["preco promocional", "preço promocional", "promocao", "promo", "discount price"],
  priceOnRequest: ["sob consulta", "preco sob consulta", "preço sob consulta", "price on request"],
  unitType: ["tipo unidade", "tipo de unidade", "unit type", "unidade"],
};

function normalizeHeader(value: unknown) {
  return String(value ?? "")
    .trim()
    .toLowerCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[\s-]+/g, "_")
    .replace(/[^a-z0-9_]/g, "")
    .replace(/_+/g, "_")
    .replace(/^_+|_+$/g, "");
}

function normalizeComparableText(value: unknown) {
  return String(value ?? "")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLowerCase()
    .replace(/[_-]+/g, " ")
    .replace(/[^\p{L}\p{N}\s]/gu, " ")
    .replace(/\s+/g, " ")
    .trim();
}

function normalizeAttributeKey(value: unknown) {
  return normalizeComparableText(value).replace(/\s+/g, "_");
}

function normalizeString(value: unknown) {
  return String(value ?? "").trim();
}

function parseMoney(value: unknown) {
  if (typeof value === "number" && !Number.isNaN(value)) return value;
  if (typeof value !== "string") return null;
  const trimmed = value.trim();
  if (!trimmed) return null;
  const cleaned = trimmed.replace(/[^\d,.-]/g, "");
  if (!cleaned) return null;
  const lastComma = cleaned.lastIndexOf(",");
  const lastDot = cleaned.lastIndexOf(".");
  let normalized: string;
  if (lastDot !== -1 && lastComma !== -1) {
    if (lastComma > lastDot) {
      normalized = cleaned.replace(/\./g, "").replace(",", ".");
    } else {
      normalized = cleaned.replace(/,/g, "");
    }
  } else if (lastComma !== -1) {
    normalized = cleaned.replace(",", ".");
  } else {
    normalized = cleaned;
  }
  const parsed = Number.parseFloat(normalized);
  return Number.isNaN(parsed) ? null : parsed;
}

function parseNumber(value: unknown) {
  return parseMoney(value);
}

function parsePriceOnRequestFromValue(value: unknown) {
  if (typeof value === "boolean") return value;
  if (typeof value === "number") return value > 0;
  if (typeof value !== "string") return false;
  const normalized = normalizeComparableText(value);
  return normalized === "sob consulta" || normalized === "sob consulta price" || normalized === "price on request";
}

function parseBoolean(value: unknown, fallback = false) {
  if (typeof value === "boolean") return value;
  if (typeof value === "number") return value > 0;
  if (typeof value !== "string") return fallback;
  const normalized = normalizeComparableText(value);
  if (["sim", "yes", "true", "1", "ativo", "active", "habilitado", "enabled"].includes(normalized)) return true;
  if (["nao", "não", "no", "false", "0", "inativo", "inactive", "desabilitado", "disabled"].includes(normalized)) return false;
  return fallback;
}

function splitImages(value: unknown) {
  if (!value) return [];
  if (Array.isArray(value)) return value.map((v) => String(v).trim()).filter(Boolean);
  return String(value)
    .split(/[,;|\n]/g)
    .map((v) => v.trim())
    .filter(Boolean);
}

function parseCategoryPath(value: unknown) {
  const raw = normalizeString(value);
  if (!raw) return [];
  return raw
    .split(/[>/|]/g)
    .map((part) => part.trim())
    .filter(Boolean);
}

function detectColumnIndex(
  normalizedComparableHeaders: string[],
  aliases: string[],
  usedIndexes: Set<number>
) {
  const normalizedAliases = aliases.map((alias) => normalizeComparableText(alias)).filter(Boolean);
  for (const alias of normalizedAliases) {
    const exactIndex = normalizedComparableHeaders.findIndex(
      (header, index) => !usedIndexes.has(index) && header === alias
    );
    if (exactIndex >= 0) return exactIndex;
  }
  for (const alias of normalizedAliases) {
    const partialIndex = normalizedComparableHeaders.findIndex(
      (header, index) =>
        !usedIndexes.has(index) &&
        !!header &&
        (header.includes(alias) || alias.includes(header))
    );
    if (partialIndex >= 0) return partialIndex;
  }
  return -1;
}

function detectStockColumnIndex(
  normalizedComparableHeaders: string[],
  usedIndexes: Set<number>
) {
  const aliases = standardFieldAliases.estoque.map((alias) => normalizeComparableText(alias)).filter(Boolean);
  const excludedTokens = [
    "min",
    "minimo",
    "mínimo",
    "max",
    "maximo",
    "máximo",
    "safety",
    "seguranca",
    "segurança",
    "reservado",
    "reorder",
    "ponto pedido",
  ].map((value) => normalizeComparableText(value));

  const isExcluded = (header: string) => excludedTokens.some((token) => token && header.includes(token));

  for (const alias of aliases) {
    const exactIndex = normalizedComparableHeaders.findIndex(
      (header, index) => !usedIndexes.has(index) && header === alias
    );
    if (exactIndex >= 0 && !isExcluded(normalizedComparableHeaders[exactIndex])) return exactIndex;
  }

  let bestIndex = -1;
  let bestScore = -1;

  normalizedComparableHeaders.forEach((header, index) => {
    if (!header || usedIndexes.has(index) || isExcluded(header)) return;
    let score = 0;
    for (const alias of aliases) {
      if (header === alias) score += 10;
      else if (header.includes(alias) || alias.includes(header)) score += 4;
    }
    if (
      header.includes("estoque") ||
      header.includes("stock") ||
      header.includes("inventory") ||
      header.includes("quantidade") ||
      header.includes("qtd") ||
      header.includes("qtde") ||
      header.includes("saldo") ||
      header.includes("disponivel") ||
      header.includes("disponível")
    ) {
      score += 3;
    }
    if (score > bestScore) {
      bestScore = score;
      bestIndex = index;
    }
  });

  return bestScore > 0 ? bestIndex : -1;
}

function detectStandardColumnMapping(headers: string[]) {
  const normalizedComparableHeaders = headers.map((header) => normalizeComparableText(header));
  const usedIndexes = new Set<number>();
  const mapping: Partial<Record<StandardProductField, number>> = {};

  const namePrimaryIndex = detectColumnIndex(normalizedComparableHeaders, namePrimaryAliases, usedIndexes);
  if (namePrimaryIndex >= 0) {
    mapping.nome = namePrimaryIndex;
    usedIndexes.add(namePrimaryIndex);
  }

  const descriptionIndex = detectColumnIndex(
    normalizedComparableHeaders,
    standardFieldAliases.descricao,
    usedIndexes
  );
  if (descriptionIndex >= 0) {
    mapping.descricao = descriptionIndex;
    usedIndexes.add(descriptionIndex);
  }

  if (typeof mapping.nome !== "number") {
    const nameFallbackIndex = detectColumnIndex(normalizedComparableHeaders, nameFallbackAliases, usedIndexes);
    if (nameFallbackIndex >= 0) {
      mapping.nome = nameFallbackIndex;
      usedIndexes.add(nameFallbackIndex);
    }
  }

  (["preco", "ativo", "categoria", "sku"] as const).forEach((field) => {
    const index = detectColumnIndex(normalizedComparableHeaders, standardFieldAliases[field], usedIndexes);
    if (index >= 0) {
      mapping[field] = index;
      usedIndexes.add(index);
    }
  });

  const stockIndex = detectStockColumnIndex(normalizedComparableHeaders, usedIndexes);
  if (stockIndex >= 0) {
    mapping.estoque = stockIndex;
    usedIndexes.add(stockIndex);
  }

  if (typeof mapping.nome !== "number" && typeof mapping.descricao === "number") {
    mapping.nome = mapping.descricao;
  }

  return mapping;
}

function countDetectedStandardFields(mapping: Partial<Record<StandardProductField, number>>) {
  return (["nome", "preco", "estoque", "ativo", "descricao", "categoria", "sku"] as const).reduce(
    (acc, field) => (typeof mapping[field] === "number" ? acc + 1 : acc),
    0
  );
}

function detectBestHeaderRow(rows: unknown[][]) {
  const maxRowsToAnalyze = Math.min(rows.length, 25);
  let bestIndex = 0;
  let bestScore = -1;

  for (let index = 0; index < maxRowsToAnalyze; index += 1) {
    const candidate = rows[index] ?? [];
    const headers = candidate.map((cell) => String(cell ?? "").trim());
    const nonEmptyHeaders = headers.filter((header) => header.length > 0).length;
    if (!nonEmptyHeaders) continue;
    const mapping = detectStandardColumnMapping(headers);
    const mappedCount = countDetectedStandardFields(mapping);
    const score = mappedCount * 100 + Math.min(nonEmptyHeaders, 20);
    if (score > bestScore) {
      bestScore = score;
      bestIndex = index;
    }
  }

  return bestIndex;
}

function detectTechnicalColumns(headers: string[], reservedIndexes: Set<number>) {
  const normalizedComparableHeaders = headers.map((header) => normalizeComparableText(header));
  const usedIndexes = new Set(reservedIndexes);
  const images = detectColumnIndex(normalizedComparableHeaders, technicalFieldAliases.images, usedIndexes);
  if (images >= 0) usedIndexes.add(images);
  const pricePromotional = detectColumnIndex(
    normalizedComparableHeaders,
    technicalFieldAliases.pricePromotional,
    usedIndexes
  );
  if (pricePromotional >= 0) usedIndexes.add(pricePromotional);
  const priceOnRequest = detectColumnIndex(
    normalizedComparableHeaders,
    technicalFieldAliases.priceOnRequest,
    usedIndexes
  );
  if (priceOnRequest >= 0) usedIndexes.add(priceOnRequest);
  const unitType = detectColumnIndex(normalizedComparableHeaders, technicalFieldAliases.unitType, usedIndexes);

  return {
    images: images >= 0 ? images : null,
    pricePromotional: pricePromotional >= 0 ? pricePromotional : null,
    priceOnRequest: priceOnRequest >= 0 ? priceOnRequest : null,
    unitType: unitType >= 0 ? unitType : null,
  };
}

function detectAttributeColumns(headers: string[], reservedIndexes: Set<number>) {
  const attributes: DetectedAttributeColumn[] = [];
  headers.forEach((header, index) => {
    if (reservedIndexes.has(index)) return;
    const attributeKey = normalizeAttributeKey(header);
    if (!attributeKey) return;
    attributes.push({
      index,
      key: attributeKey,
    });
  });
  return attributes;
}

function getMappedHeaderName(
  preview: ImportPreview,
  field: StandardProductField
) {
  const index = preview.columnMapping[field];
  if (typeof index !== "number" || index < 0) return null;
  const header = preview.headers[index];
  const headerValue = String(header ?? "").trim();
  return headerValue || null;
}

function getCellValue(row: unknown[], index?: number | null) {
  if (typeof index !== "number" || index < 0) return null;
  return row[index];
}

function resolveMoneyFromIndexes(row: unknown[], indexes: Array<number | null | undefined>) {
  for (const index of indexes) {
    const value = parseMoney(getCellValue(row, index));
    if (value !== null) return value;
  }
  return null;
}

function stripDescriptionFormatting(value: unknown) {
  const raw = normalizeString(value);
  if (!raw) return "";
  const withBreaks = raw
    .replace(/<\s*br\s*\/?>/gi, "\n")
    .replace(/<\/\s*p\s*>/gi, "\n");
  const withoutTags = withBreaks.replace(/<[^>]*>/g, " ");
  return withoutTags
    .replace(/&nbsp;/gi, " ")
    .replace(/&amp;/gi, "&")
    .replace(/&lt;/gi, "<")
    .replace(/&gt;/gi, ">")
    .replace(/[ \t]+/g, " ")
    .replace(/\n{3,}/g, "\n\n")
    .trim();
}

function resolvePriceValueFromRow(
  row: unknown[],
  mapping: Partial<Record<StandardProductField, number>>,
  technicalMapping: { pricePromotional: number | null }
) {
  const direct = resolveMoneyFromIndexes(row, [mapping.preco, technicalMapping.pricePromotional]);
  return direct ?? 0;
}

function resolvePromoPriceFromRow(
  row: unknown[],
  technicalMapping: { pricePromotional: number | null }
) {
  return parseMoney(getCellValue(row, technicalMapping.pricePromotional));
}

function parseImportOptionValue(value: unknown): ImportOptionValue | null {
  if (!value) return null;
  const str = String(value).trim();
  if (!str) return null;
  return { name: str, value: str };
}

function parseImportOptionValues(value: unknown): ImportOptionValue[] {
  if (!value) return [];
  if (Array.isArray(value)) {
    return value
      .map(parseImportOptionValue)
      .filter((v): v is ImportOptionValue => v !== null);
  }
  return String(value)
    .split(/[,;|\n]/g)
    .map(parseImportOptionValue)
    .filter((v): v is ImportOptionValue => v !== null);
}

function parseUnitType(value: unknown) {
  if (typeof value !== "string") return "unit";
  const normalized = normalizeHeader(value);
  if (unitTypeValues.has(normalized)) return normalized;
  return "unit";
}

type ProductImportRow = {
  rowNumber: number;
  name: string;
  sku: string;
  description: string;
  categoryPath: string[];
  price: number | null;
  pricePromotional: number | null;
  stock: number | null;
  active: boolean;
  priceOnRequest: boolean;
  images: string[];
  unitType: string;
  importOptionValues: ImportOptionValue[];
  attributes: Record<string, string>;
};

function parseProductFromRow(
  rowNumber: number,
  row: unknown[],
  mapping: Partial<Record<StandardProductField, number>>,
  technicalMapping: {
    images: number | null;
    pricePromotional: number | null;
    priceOnRequest: number | null;
    unitType: number | null;
  },
  attributeColumns: DetectedAttributeColumn[]
): ProductImportRow {
  const name = normalizeString(getCellValue(row, mapping.nome));
  const sku = normalizeString(getCellValue(row, mapping.sku));
  const description = stripDescriptionFormatting(getCellValue(row, mapping.descricao));
  const categoryPath = parseCategoryPath(getCellValue(row, mapping.categoria));
  const price = resolvePriceValueFromRow(row, mapping, technicalMapping);
  const pricePromotional = resolvePromoPriceFromRow(row, technicalMapping);
  const stock = parseNumber(getCellValue(row, mapping.estoque)) ?? 0;
  const active = parseBoolean(getCellValue(row, mapping.ativo), true);
  const priceOnRequest = parsePriceOnRequestFromValue(getCellValue(row, technicalMapping.priceOnRequest));
  const images = Array.from(new Set(splitImages(getCellValue(row, technicalMapping.images))));
  const unitType = parseUnitType(getCellValue(row, technicalMapping.unitType));
  const importOptionValues = parseImportOptionValues(undefined);
  const attributes = attributeColumns.reduce((acc, attribute) => {
    const rawValue = normalizeString(getCellValue(row, attribute.index));
    if (!rawValue) return acc;
    acc[attribute.key] = rawValue;
    return acc;
  }, {} as Record<string, string>);

  return {
    rowNumber,
    name,
    sku,
    description,
    categoryPath,
    price,
    pricePromotional,
    stock,
    active,
    priceOnRequest,
    images,
    unitType,
    importOptionValues,
    attributes,
  };
}

type ImportPayloadVariation = {
  combination: Record<string, string>;
  sku?: string;
  price: number;
  stock: number;
};

type ImportPayloadAttribute = {
  name: string;
  options: string[];
  allow_multiple: boolean;
  is_required: boolean;
  position: number;
};

type ImportPayloadRow = {
  rowNumber: number;
  name: string;
  sku?: string;
  description: string;
  categoryPath: string[];
  price: number | null;
  pricePromotional: number | null;
  priceOnRequest: boolean;
  stock: number | null;
  unitType: string;
  active: boolean;
  imageUrls: string[];
  attributes: ImportPayloadAttribute[];
  variations: ImportPayloadVariation[];
};

function buildImportPayloadRows(rows: ProductImportRow[]): ImportPayloadRow[] {
  const grouped = new Map<string, ProductImportRow[]>();
  rows.forEach((row) => {
    const normalizedName = normalizeComparableText(row.name);
    const normalizedDescription = normalizeComparableText(row.description);
    const normalizedCategory = normalizeComparableText(row.categoryPath.join(" > "));
    const key = normalizedName
      ? [normalizedName, normalizedDescription, normalizedCategory].join("|")
      : `row-${row.rowNumber}`;
    const current = grouped.get(key);
    if (current) {
      current.push(row);
    } else {
      grouped.set(key, [row]);
    }
  });

  const payloadRows: ImportPayloadRow[] = [];

  grouped.forEach((groupRows) => {
    const firstRow = groupRows[0];
    const hasAnyAttributes = groupRows.some((row) => Object.keys(row.attributes).length > 0);
    const shouldCreateVariations = hasAnyAttributes && groupRows.length > 1;

    if (!shouldCreateVariations) {
      groupRows.forEach((row) => {
        const attributeEntries = Object.entries(row.attributes);
        const attributes =
          attributeEntries.length > 0
            ? attributeEntries.map(([name, value], index) => ({
                name,
                options: [value],
                allow_multiple: false,
                is_required: false,
                position: index,
              }))
            : [];
        payloadRows.push({
          rowNumber: row.rowNumber,
          name: row.name,
          sku: row.sku || undefined,
          description: row.description,
          categoryPath: row.categoryPath,
          price: row.price,
          pricePromotional: row.pricePromotional,
          priceOnRequest: row.priceOnRequest,
          stock: row.stock,
          unitType: row.unitType,
          active: row.active,
          imageUrls: row.images,
          attributes,
          variations: [],
        });
      });
      return;
    }

    const attributeOptionsMap = new Map<string, Set<string>>();
    const variations: ImportPayloadVariation[] = groupRows.map((row) => {
      const combination: Record<string, string> = {};
      Object.entries(row.attributes).forEach(([name, value]) => {
        if (!attributeOptionsMap.has(name)) {
          attributeOptionsMap.set(name, new Set());
        }
        attributeOptionsMap.get(name)?.add(value);
        combination[name] = value;
      });
      return {
        combination,
        sku: row.sku || undefined,
        price: row.price ?? 0,
        stock: row.stock ?? 0,
      };
    });

    const attributes = Array.from(attributeOptionsMap.entries()).map(([name, values], index) => ({
      name,
      options: Array.from(values),
      allow_multiple: false,
      is_required: false,
      position: index,
    }));

    payloadRows.push({
      rowNumber: firstRow.rowNumber,
      name: firstRow.name,
      sku: firstRow.sku || undefined,
      description: firstRow.description,
      categoryPath: firstRow.categoryPath,
      price: firstRow.price,
      pricePromotional: firstRow.pricePromotional,
      priceOnRequest: firstRow.priceOnRequest,
      stock: variations.reduce((acc, variation) => acc + variation.stock, 0),
      unitType: firstRow.unitType,
      active: firstRow.active,
      imageUrls: Array.from(new Set(groupRows.flatMap((row) => row.images))),
      attributes,
      variations,
    });
  });

  return payloadRows;
}

const passthroughLoader = ({ src }: { src: string }) => src;

function ProductImageHover({ product }: { product: Product }) {
  const [isHovered, setIsHovered] = useState(false);
  const [currentIndex, setCurrentIndex] = useState(0);

  const allImages = useMemo(() => {
    const images: string[] = [];
    if (product.image_url) images.push(product.image_url);
    if ((product as any).product_images) {
      const sorted = [...(product as any).product_images].sort((a: any, b: any) => (a.sort_order || 0) - (b.sort_order || 0));
      sorted.forEach((img: any) => {
        if (img.image_url && img.image_url !== product.image_url) images.push(img.image_url);
      });
    }
    return images;
  }, [product]);

  useEffect(() => {
    let interval: NodeJS.Timeout;
    if (isHovered && allImages.length > 1) {
      interval = setInterval(() => {
        setCurrentIndex(prev => (prev + 1) % allImages.length);
      }, 1500);
    } else {
      setCurrentIndex(0);
    }
    return () => clearInterval(interval);
  }, [isHovered, allImages.length]);

  const currentImage = allImages.length > 0 ? allImages[currentIndex] : null;

  return (
    <div 
      className="relative w-full h-full group/image"
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      {currentImage ? (
        <Image
          src={miniatura(currentImage, 480)}
          alt={product.name}
          fill
          className="object-cover transition-transform duration-500 group-hover/image:scale-110"
          loader={passthroughLoader}
          unoptimized
        />
      ) : (
        <div className="absolute inset-0 flex items-center justify-center text-muted-foreground bg-gray-50">
          <Package className="h-8 w-8 text-gray-400" />
        </div>
      )}

      <div className="absolute inset-0 bg-black/30 opacity-0 group-hover/image:opacity-100 transition-opacity duration-300 flex items-center justify-center backdrop-blur-[1px]">
        <div className="flex items-center gap-2 text-white bg-white/20 px-3 py-1.5 rounded-full backdrop-blur-md transform translate-y-4 group-hover/image:translate-y-0 transition-all duration-300">
          <Eye size={16} />
          <span className="text-sm font-medium">Ver detalhes</span>
        </div>
      </div>
    </div>
  );
}

export default function ProductsPage() {
  const { pode } = usePermissoes();
  /* Ver produtos e uma coisa; mexer neles e outra. Quem so ve continua
     abrindo a tela e a ficha, sem os botoes que a API recusaria. */
  const podeMexerEmProdutos = pode("products.catalog.write");

  const [products, setProducts] = useState<Product[]>([]);
  /* Estoque novo (v2): o estoque de cada produto pela conta nova (pronto /
     sob encomenda / não controla). Fora do v2, o "Estoque: N" de sempre. */
  const estoqueNovo = useEstoqueV2();
  const idsDosProdutos = useMemo(() => products.map((p) => p.id), [products]);
  const estoqueDaLista = useEstoqueDaLista(estoqueNovo.v2, idsDosProdutos);
  const [loading, setLoading] = useState(true);
  const [searchTerm, setSearchTerm] = useState("");
  const [sortBy, setSortBy] = useState("name_asc");
  const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false);
  const [imageFilter, setImageFilter] = useState("all");
  const [priceFilter, setPriceFilter] = useState("all");
  const [descriptionFilter, setDescriptionFilter] = useState("all");
  const [stockFilter, setStockFilter] = useState("all");
  const [categoryFilter, setCategoryFilter] = useState("all");
  const [actionsOpen, setActionsOpen] = useState(false);
  const [duplicatingProductId, setDuplicatingProductId] = useState<string | null>(null);
  const [previewProductId, setPreviewProductId] = useState<string | null>(null);
  const actionsRef = useRef<HTMLDivElement>(null);
  /* O menu de acoes em massa existe duas vezes: um na barra do desktop, outro
     na barra compacta do celular. So um fica visivel por vez, mas os dois ficam
     no DOM — sem o segundo ref, clicar no gatilho do celular contava como
     "clique fora" do bloco do desktop e o menu fechava no mesmo instante. */
  const actionsRefMobile = useRef<HTMLDivElement>(null);

  useEffect(() => {
    function handleClickOutside(event: MouseEvent) {
      const alvo = event.target as Node;
      const dentroDesktop = actionsRef.current?.contains(alvo);
      const dentroMobile = actionsRefMobile.current?.contains(alvo);
      if (!dentroDesktop && !dentroMobile) {
        setActionsOpen(false);
      }
    }

    if (actionsOpen) {
      document.addEventListener("mousedown", handleClickOutside);
    }

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [actionsOpen]);
  const [viewMode, setViewMode] = useState<"cards" | "list">("cards");
  const [categories, setCategories] = useState<Array<{ id: string; name: string }>>([]);
  const [importOpen, setImportOpen] = useState(false);
  const [importPreview, setImportPreview] = useState<ImportPreview | null>(null);
  const [importFileName, setImportFileName] = useState<string | null>(null);
  const [importing, setImporting] = useState(false);
  const [importCancelDialogOpen, setImportCancelDialogOpen] = useState(false);
  const importCancelRequestedRef = useRef(false);
  const [importProgress, setImportProgress] = useState<{
    total: number;
    processed: number;
    created: number;
    cancelRequested: boolean;
  }>({ total: 0, processed: 0, created: 0, cancelRequested: false });
  const [importResult, setImportResult] = useState<ImportResult | null>(null);
  const [selectedProducts, setSelectedProducts] = useState<Set<string>>(new Set());
  const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
  const [deleteStatus, setDeleteStatus] = useState<{
    loading: boolean;
    linkedProducts: Array<{ id: string; name: string; quoteCount: number; orderCount: number }>;
    forceDelete: boolean;
  }>({ loading: false, linkedProducts: [], forceDelete: false });
  const [bulkProgress, setBulkProgress] = useState<{
    open: boolean;
    total: number;
    deleted: number;
    finished: boolean;
  }>({ open: false, total: 0, deleted: 0, finished: false });
  const passthroughLoader = ({ src }: { src: string }) => src;

  const resetImportState = () => {
    setImportPreview(null);
    setImportFileName(null);
    setImportResult(null);
    setImporting(false);
    setImportCancelDialogOpen(false);
    importCancelRequestedRef.current = false;
    setImportProgress({ total: 0, processed: 0, created: 0, cancelRequested: false });
  };

  const handleImportOpenChange = (open: boolean) => {
    if (open) {
      setImportOpen(true);
      return;
    }
    if (importing) {
      setImportCancelDialogOpen(true);
      return;
    }
    setImportOpen(false);
    resetImportState();
  };

  const handleImportFileChange = async (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) {
      resetImportState();
      return;
    }

    try {
      setImportFileName(file.name);
      setImportResult(null);

      const data = await file.arrayBuffer();
      const workbook = XLSX.read(data, { type: "array" });
      const sheetName = workbook.SheetNames[0];
      const sheet = workbook.Sheets[sheetName];
      if (!sheet) {
        setImportPreview(null);
        return;
      }

      const rows = XLSX.utils.sheet_to_json<unknown[]>(sheet, {
        header: 1,
        defval: "",
        blankrows: false,
      }) as unknown[][];

      if (!rows.length) {
        setImportPreview(null);
        return;
      }

      const headerRowIndex = detectBestHeaderRow(rows);
      const headerRow = rows[headerRowIndex] as unknown[];
      const headers = headerRow.map((header) => String(header ?? "").trim());
      const normalizedHeaders = headers.map((header) => normalizeHeader(header));
      const columnMapping = detectStandardColumnMapping(headers);
      const reservedIndexes = new Set<number>(Object.values(columnMapping).filter((value): value is number => typeof value === "number"));
      const technicalMapping = detectTechnicalColumns(headers, reservedIndexes);
      Object.values(technicalMapping).forEach((value) => {
        if (typeof value === "number") reservedIndexes.add(value);
      });
      const attributeColumns = detectAttributeColumns(headers, reservedIndexes);
      const dataRows = rows.slice(headerRowIndex + 1);
      const parsedRows: ProductImportRow[] = [];

      dataRows.forEach((row, index) => {
        const hasValue = row.some((cell) => String(cell ?? "").trim().length > 0);
        if (!hasValue) return;

        parsedRows.push(
          parseProductFromRow(headerRowIndex + index + 2, row, columnMapping, technicalMapping, attributeColumns)
        );
      });

      setImportPreview({
        rows: parsedRows,
        headers,
        normalizedHeaders,
        columnMapping,
      });
    } catch (error) {
      console.error("Erro ao ler planilha:", error);
      setImportPreview(null);
    }
  };

  const handleStartImport = async () => {
    if (!importPreview?.rows.length) return;
    setImporting(true);
    setImportResult(null);
    importCancelRequestedRef.current = false;

    try {
      const payloadRows = buildImportPayloadRows(importPreview.rows);
      const totalRows = payloadRows.length;
      const chunkSize = 20;
      const createdProductIds: string[] = [];
      const merged: ImportResult = {
        productsCreated: 0,
        variantsCreated: 0,
        categoriesCreated: 0,
        imagesCreated: 0,
        skippedRows: 0,
        errors: [],
        createdProductIds: [],
      };

      setImportProgress({ total: totalRows, processed: 0, created: 0, cancelRequested: false });

      const rollbackImportedProducts = async (productIds: string[]) => {
        if (!productIds.length) return;
        const rollbackChunkSize = 50;
        for (let i = 0; i < productIds.length; i += rollbackChunkSize) {
          const rollbackChunk = productIds.slice(i, i + rollbackChunkSize);
          await fetch("/api/products/bulk-delete", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ productIds: rollbackChunk, forceDelete: true }),
          }).catch(() => null);
        }
      };

      for (let i = 0; i < payloadRows.length; i += chunkSize) {
        const chunk = payloadRows.slice(i, i + chunkSize);
        const response = await fetch("/api/products/import", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ rows: chunk }),
        });
        const partialResult = (await response.json().catch(() => null)) as ImportResult | { error?: string } | null;

        if (!response.ok) {
          const message = partialResult && "error" in partialResult ? partialResult.error : "Falha ao importar produtos.";
          throw new Error(message || "Falha ao importar produtos.");
        }

        if (partialResult && "productsCreated" in partialResult) {
          merged.productsCreated += partialResult.productsCreated;
          merged.variantsCreated += partialResult.variantsCreated;
          merged.categoriesCreated += partialResult.categoriesCreated;
          merged.imagesCreated += partialResult.imagesCreated;
          merged.skippedRows += partialResult.skippedRows;
          merged.errors.push(...partialResult.errors);
          const partialCreatedIds = Array.isArray(partialResult.createdProductIds) ? partialResult.createdProductIds : [];
          createdProductIds.push(...partialCreatedIds);
          merged.createdProductIds = createdProductIds;
          setImportProgress((prev) => ({
            ...prev,
            processed: Math.min(totalRows, prev.processed + chunk.length),
            created: merged.productsCreated,
          }));
        } else {
          setImportProgress((prev) => ({
            ...prev,
            processed: Math.min(totalRows, prev.processed + chunk.length),
          }));
        }

        if (importCancelRequestedRef.current) {
          break;
        }
      }

      if (importCancelRequestedRef.current) {
        await rollbackImportedProducts(createdProductIds);
        await loadProducts();
        resetImportState();
        setImportOpen(false);
        return;
      }

      setImportResult(merged);
      await loadProducts();
    } catch (error) {
      const message = error instanceof Error ? error.message : "Falha ao importar produtos.";
      setImportResult({
        productsCreated: 0,
        variantsCreated: 0,
        categoriesCreated: 0,
        imagesCreated: 0,
        skippedRows: importPreview.rows.length,
        errors: [{ rowNumber: 0, message }],
        createdProductIds: [],
      });
    } finally {
      setImporting(false);
    }
  };

  const handleClearImport = () => {
    resetImportState();
  };

  const requestCancelImport = () => {
    if (!importing) {
      setImportCancelDialogOpen(false);
      setImportOpen(false);
      resetImportState();
      return;
    }
    importCancelRequestedRef.current = true;
    setImportCancelDialogOpen(false);
    setImportProgress((prev) => ({ ...prev, cancelRequested: true }));
  };

  // Funções para seleção múltipla
  const toggleProductSelection = (productId: string) => {
    const newSelection = new Set(selectedProducts);
    if (newSelection.has(productId)) {
      newSelection.delete(productId);
    } else {
      newSelection.add(productId);
    }
    setSelectedProducts(newSelection);
  };

  const toggleSelectAll = () => {
    if (selectedProducts.size === products.length) {
      setSelectedProducts(new Set());
    } else {
      setSelectedProducts(new Set(products.map(p => p.id)));
    }
  };

  const performBulkDelete = async (productIds: string[], forceDelete: boolean) => {
    if (productIds.length === 0) return;

    setDeleteStatus((prev) => ({ ...prev, loading: true }));
    const isBulk = productIds.length > 1;
    if (isBulk) {
      setBulkProgress({ open: true, total: productIds.length, deleted: 0, finished: false });
    }

    try {
      const chunkSize = 50;
      const chunks: string[][] = [];
      for (let i = 0; i < productIds.length; i += chunkSize) {
        chunks.push(productIds.slice(i, i + chunkSize));
      }

      const linkedMap = new Map<string, { id: string; name: string; quoteCount: number; orderCount: number }>();
      let deletedCount = 0;

      for (const chunk of chunks) {
        const response = await fetch("/api/products/bulk-delete", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            productIds: chunk,
            forceDelete,
          }),
        });

        if (!response.ok) {
          const errorBody = (await response.json().catch(() => null)) as { error?: string } | null;
          throw new Error(errorBody?.error || "Falha ao excluir produtos");
        }

        const result = await response.json();
        deletedCount += typeof result.deletedCount === "number" ? result.deletedCount : 0;
        if (isBulk) {
          setBulkProgress((prev) => ({
            ...prev,
            deleted: Math.min(prev.total, prev.deleted + (typeof result.deletedCount === "number" ? result.deletedCount : 0)),
          }));
        }

        if (Array.isArray(result.linkedProducts)) {
          for (const product of result.linkedProducts) {
            if (!product?.id) continue;
            linkedMap.set(product.id, product);
          }
        }
      }

      const linked = Array.from(linkedMap.values());
      const linkedIds = linked.map((product) => product.id);

      if (!forceDelete && linked.length > 0) {
        if (deletedCount > 0) {
          await loadProducts();
        }
        setSelectedProducts(new Set(linkedIds));
        setDeleteStatus({
          loading: false,
          linkedProducts: linked,
          forceDelete: true,
        });
        if (isBulk) {
          setBulkProgress((prev) => ({ ...prev, finished: true, open: false }));
        }
        setIsDeleteDialogOpen(true);
        return;
      }

      await loadProducts();
      setSelectedProducts(new Set());
      setIsDeleteDialogOpen(false);
      setDeleteStatus({ loading: false, linkedProducts: [], forceDelete: false });
      if (isBulk) {
        setBulkProgress((prev) => ({ ...prev, finished: true, deleted: prev.total }));
      }
    } catch (error) {
      console.error("Erro ao excluir produtos:", error);
      setDeleteStatus({ loading: false, linkedProducts: [], forceDelete: false });
      if (isBulk) {
        setBulkProgress((prev) => ({ ...prev, finished: true, open: false }));
      }
    }
  };

  const handleBulkDelete = async () => {
    await performBulkDelete(Array.from(selectedProducts), false);
  };

  const handleConfirmDelete = async () => {
    await performBulkDelete(Array.from(selectedProducts), true);
  };

  const handleSingleDelete = async (productId: string) => {
    setSelectedProducts(new Set([productId]));
    await performBulkDelete([productId], false);
  };

  const handleDuplicateProduct = async (productId: string) => {
    try {
      setDuplicatingProductId(productId);
      const supabase = getSupabaseClient();
      const { data: { user } } = await supabase.auth.getUser();
      if (!user) throw new Error("Não autenticado");

      /* A cópia é feita pelo banco, numa transação só (migration 208): ids
         novos para cada opção — o saldo por opção é guardado pelo id dela, e
         copiar o id fazia as duas peças dividirem o mesmo estoque —, estoque
         zerado, e junto as receitas e tempos da opção, os serviços, as faixas,
         as fotos (com a foto de cada opção), os processos e a composição. */
      const { error: copiaError } = await supabase.rpc("duplicar_produto", { p_produto: productId });
      if (copiaError) throw copiaError;

      toast.success("Produto duplicado com sucesso!");
      await loadProducts();

    } catch (error) {
      console.error("Erro ao duplicar produto:", error);
      toast.error("Erro ao duplicar o produto.");
    } finally {
      setDuplicatingProductId(null);
    }
  };

  const loadProducts = async () => {
    const supabase = getSupabaseClient();
    const { data: { user } } = await supabase.auth.getUser();
    if (!user) return;
    
    const ctx = await getCompanyContext(supabase, user);
    const tenantIds = ctx.tenantIds?.length ? ctx.tenantIds : [user.id];

    const { data, error } = await supabase
      .from("products")
      .select("*, product_images(image_url, sort_order)")
      .in("user_id", tenantIds)
      .neq("product_kind", "digital")
      .order("name");

    if (error) {
      console.error("Error loading products:", error);
    } else {
      setProducts(data || []);
    }
    setLoading(false);
  };

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

    async function run() {
      const supabase = getSupabaseClient();

      const {
        data: { user },
      } = await supabase.auth.getUser();
      if (!user) return;
      const ctx = await getCompanyContext(supabase, user);
      const tenantIds = ctx.tenantIds?.length ? ctx.tenantIds : [user.id];

      const { data, error } = await supabase
        .from("products")
        .select("*, product_images(image_url, sort_order)")
        .in("user_id", tenantIds)
        .neq("product_kind", "digital")
        .order("name");

      if (cancelled) return;

      if (error) {
        console.error("Error loading products:", error);
      } else {
        setProducts(data || []);
      }
      setLoading(false);

      const { data: cats } = await supabase
        .from("categories")
        .select("id,name")
        .in("user_id", tenantIds)
        .order("name");
      if (!cancelled) setCategories((cats as Array<{ id: string; name: string }>) || []);
    }

    run();

    return () => {
      cancelled = true;
    };
  }, []);

  const filteredProducts = useMemo(() => {
    const term = searchTerm.toLowerCase();
    let list = products.filter((p) => {
      const matchesSearch =
        !term ||
        p.name.toLowerCase().includes(term) ||
        p.id.toLowerCase().includes(term);
      if (!matchesSearch) return false;
      if (imageFilter === "with" && !p.image_url) return false;
      if (imageFilter === "without" && p.image_url) return false;
      if (priceFilter === "with" && !(typeof p.price === "number" && p.price > 0)) return false;
      if (priceFilter === "without" && (typeof p.price === "number" && p.price > 0)) return false;
      const hasDesc = typeof p.description === "string" && p.description.trim().length > 0;
      if (descriptionFilter === "with" && !hasDesc) return false;
      if (descriptionFilter === "without" && hasDesc) return false;
      const hasStock = typeof p.stock === "number" && p.stock > 0;
      if (stockFilter === "with" && !hasStock) return false;
      if (stockFilter === "without" && hasStock) return false;
      if (categoryFilter !== "all" && p.category_id !== categoryFilter) return false;
      return true;
    });
    if (sortBy === "price_desc") {
      list = [...list].sort((a, b) => (b.price || 0) - (a.price || 0));
    } else if (sortBy === "price_asc") {
      list = [...list].sort((a, b) => (a.price || 0) - (b.price || 0));
    } else {
      list = [...list].sort((a, b) => a.name.localeCompare(b.name));
    }
    return list;
  }, [products, searchTerm, imageFilter, priceFilter, descriptionFilter, stockFilter, categoryFilter, sortBy]);

  /* Definicao unica dos filtros: a barra do desktop e o painel do celular leem
     daqui. Duplicar as listas nos dois lugares fazia com que mexer num rotulo
     ou numa opcao so valesse para metade da tela. */
  const filtrosProduto = [
    {
      id: "categoria",
      rotulo: "Categoria",
      valor: categoryFilter,
      aplicar: setCategoryFilter,
      opcoes: [
        { value: "all", label: "Todas categorias" },
        ...categories.map((c) => ({ value: c.id, label: c.name })),
      ],
    },
    {
      id: "imagem",
      rotulo: "Imagem",
      valor: imageFilter,
      aplicar: setImageFilter,
      opcoes: [
        { value: "all", label: "Imagem: Todas" },
        { value: "with", label: "Com foto" },
        { value: "without", label: "Sem foto" },
      ],
    },
    {
      id: "preco",
      rotulo: "Preço",
      valor: priceFilter,
      aplicar: setPriceFilter,
      opcoes: [
        { value: "all", label: "Preço: Todos" },
        { value: "with", label: "Com preço" },
        { value: "without", label: "Sem preço" },
      ],
    },
    {
      id: "descricao",
      rotulo: "Descrição",
      valor: descriptionFilter,
      aplicar: setDescriptionFilter,
      opcoes: [
        { value: "all", label: "Desc.: Todas" },
        { value: "with", label: "Com descrição" },
        { value: "without", label: "Sem descrição" },
      ],
    },
    {
      id: "estoque",
      rotulo: "Estoque",
      valor: stockFilter,
      aplicar: setStockFilter,
      opcoes: [
        { value: "all", label: "Estoque: Todos" },
        { value: "with", label: "Com estoque" },
        { value: "without", label: "Sem estoque" },
      ],
    },
  ];

  const opcoesOrdenacao = [
    { value: "name_asc", label: "Nome A–Z" },
    { value: "price_desc", label: "Maior preço" },
    { value: "price_asc", label: "Menor preço" },
  ];

  const filtrosAtivos = filtrosProduto.filter((f) => f.valor !== "all").length;
  const limparFiltros = () => filtrosProduto.forEach((f) => f.aplicar("all"));

  const totaisProdutos = {
    total: products.length,
    comFoto: products.filter((p) => Boolean(p.image_url)).length,
    esgotados: products.filter((p) => (p as { track_inventory?: boolean }).track_inventory === true && (p.stock || 0) <= 0).length,
  };

  if (loading) {
    return (
      <div className="flex items-center justify-center h-64">
        <Loader2 className="h-8 w-8 animate-spin" />
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <PageHeader
        title="Produtos"
        subtitle="Gerencie seu catálogo de produtos"
        actions={
          podeMexerEmProdutos
            ? [
                <Link key="new" href="/dashboard/products/new">
                  <Button icon={<Plus size={16} />}>Novo Produto</Button>
                </Link>,
                <Button
                  key="import"
                  variant="secondary"
                  onClick={() => setImportOpen(true)}
                  icon={<FileUp size={16} />}
                >
                  Importar
                </Button>,
              ]
            : []
        }
      />

      <div className="ks-surface rounded-xl shadow-sm border border-[var(--ks-color-border-subtle)]">
        <div className="p-3 md:p-4 flex flex-col lg:flex-row gap-3 md:gap-4 lg:items-center">
          <div className="flex-1 lg:min-w-[240px]">
            <Input
              placeholder="Buscar produtos..."
              value={searchTerm}
              onChange={(e) => setSearchTerm(e.target.value)}
              icon={<Search size={16} />}
              className="bg-transparent border-[var(--ks-color-border-subtle)]"
            />
          </div>

          {/* ---------- Controles do desktop (inalterados) ---------- */}
          <div className="hidden md:flex flex-wrap items-center gap-2">
            <CustomSelect
              options={opcoesOrdenacao}
              value={sortBy}
              onChange={setSortBy}
              className="w-[160px]"
            />
            <CustomSelect
              options={filtrosProduto[0].opcoes}
              value={filtrosProduto[0].valor}
              onChange={filtrosProduto[0].aplicar}
              className="w-[200px]"
            />
            <div className="w-px h-8 bg-[var(--ks-color-border-subtle)] mx-2 hidden lg:block" />
            <div className="flex bg-[var(--ks-color-bg-subtle)] p-1 rounded-lg border border-[var(--ks-color-border-subtle)]">
              <button
                type="button"
                onClick={() => setViewMode("list")}
                className={`p-1.5 rounded-md transition-all ${viewMode === "list" ? "bg-white shadow-sm text-primary" : "text-muted-foreground hover:text-foreground"}`}
                title="Lista"
              >
                <List size={16} />
              </button>
              <button
                type="button"
                onClick={() => setViewMode("cards")}
                className={`p-1.5 rounded-md transition-all ${viewMode === "cards" ? "bg-white shadow-sm text-primary" : "text-muted-foreground hover:text-foreground"}`}
                title="Cards"
              >
                <LayoutGrid size={16} />
              </button>
            </div>
          </div>

          {/* ---------- Barra compacta do celular ----------
              Antes os 6 seletores tinham largura fixa (140–200px) e vinham
              todos abertos: quebravam em cinco fileiras e o bloco tomava mais
              de meia tela antes do primeiro produto. Agora ficam num painel
              que abre sob demanda, com contador do que esta ativo. Nada some:
              ordenacao, categoria, os quatro filtros, acoes em massa, modo de
              exibicao e os totais continuam todos aqui. */}
          <div className="flex md:hidden items-center gap-2">
            <button
              type="button"
              onClick={() => setMobileFiltersOpen((v) => !v)}
              aria-expanded={mobileFiltersOpen}
              className="flex flex-1 items-center justify-center gap-1.5 h-9 rounded-lg border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-subtle)] px-3 text-xs font-semibold text-[var(--ks-color-text-primary)] transition active:scale-[0.98]"
            >
              <Filter size={14} />
              Filtros
              {filtrosAtivos > 0 ? (
                <span className="ml-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-[var(--ks-color-primary-strong)] px-1 text-[10px] font-bold text-white">
                  {filtrosAtivos}
                </span>
              ) : null}
              <ChevronDown
                size={14}
                className={`transition-transform ${mobileFiltersOpen ? "rotate-180" : ""}`}
              />
            </button>

            <div ref={actionsRefMobile} className="relative shrink-0">
              <button
                type="button"
                onClick={() => setActionsOpen(!actionsOpen)}
                className="h-9 w-9 flex items-center justify-center rounded-lg border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-subtle)] text-gray-600 transition active:scale-95"
                title="Ações em massa"
                aria-label="Ações em massa"
              >
                <Trash2 size={15} />
              </button>
              {actionsOpen && (
                <div className="absolute right-0 top-full mt-2 w-[min(13rem,calc(100vw-2rem))] bg-white rounded-md shadow-lg border border-gray-200 z-50 p-1 flex flex-col gap-1">
                  <button
                    type="button"
                    onClick={(e) => { e.preventDefault(); toggleSelectAll(); }}
                    className="w-full text-left px-3 py-2 text-sm hover:bg-gray-100 rounded-sm flex items-center gap-2 transition-colors"
                  >
                    <CheckSquare size={14} className="text-muted-foreground" />
                    {selectedProducts.size === products.length ? "Deselecionar Todos" : "Selecionar Todos"}
                  </button>
                  {podeMexerEmProdutos ? <button
                    type="button"
                    onClick={() => { if (selectedProducts.size > 0) { handleBulkDelete(); setActionsOpen(false); } }}
                    disabled={selectedProducts.size === 0}
                    className="w-full text-left px-3 py-2 text-sm hover:bg-red-50 text-red-600 rounded-sm flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                  >
                    <Trash2 size={14} />
                    Excluir ({selectedProducts.size})
                  </button> : null}
                </div>
              )}
            </div>

            <div className="flex shrink-0 bg-[var(--ks-color-bg-subtle)] p-0.5 rounded-lg border border-[var(--ks-color-border-subtle)]">
              <button
                type="button"
                onClick={() => setViewMode("list")}
                className={`p-1.5 rounded-md transition-all ${viewMode === "list" ? "bg-white shadow-sm text-primary" : "text-muted-foreground"}`}
                title="Lista"
                aria-label="Ver em lista"
              >
                <List size={15} />
              </button>
              <button
                type="button"
                onClick={() => setViewMode("cards")}
                className={`p-1.5 rounded-md transition-all ${viewMode === "cards" ? "bg-white shadow-sm text-primary" : "text-muted-foreground"}`}
                title="Cards"
                aria-label="Ver em cards"
              >
                <LayoutGrid size={15} />
              </button>
            </div>
          </div>

          {/* Painel do celular: ordenacao + os cinco filtros, dois por linha */}
          {mobileFiltersOpen ? (
            <div className="md:hidden grid grid-cols-2 gap-2.5 rounded-lg border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-subtle)]/60 p-2.5">
              <div className="col-span-2 space-y-1">
                <span className="block text-[10px] font-bold uppercase tracking-wider text-muted-foreground">
                  Ordenar por
                </span>
                <CustomSelect
                  options={opcoesOrdenacao}
                  value={sortBy}
                  onChange={setSortBy}
                  className="w-full"
                />
              </div>

              {filtrosProduto.map((filtro) => (
                <div
                  key={filtro.id}
                  className={`space-y-1 ${filtro.id === "categoria" ? "col-span-2" : ""}`}
                >
                  <span className="block text-[10px] font-bold uppercase tracking-wider text-muted-foreground">
                    {filtro.rotulo}
                  </span>
                  <CustomSelect
                    options={filtro.opcoes}
                    value={filtro.valor}
                    onChange={filtro.aplicar}
                    className="w-full"
                  />
                </div>
              ))}

              {filtrosAtivos > 0 ? (
                <button
                  type="button"
                  onClick={limparFiltros}
                  className="col-span-2 flex items-center justify-center gap-1.5 rounded-lg border border-[var(--ks-color-border-subtle)] bg-white py-2 text-xs font-semibold text-muted-foreground transition active:scale-[0.98]"
                >
                  <RotateCcw size={13} />
                  Limpar filtros
                </button>
              ) : null}
            </div>
          ) : null}
        </div>

        {/* ---------- Barra de filtros do desktop (inalterada) ---------- */}
        <div className="hidden md:flex px-4 py-3 bg-[var(--ks-color-bg-subtle)]/50 border-t border-[var(--ks-color-border-subtle)] rounded-b-xl flex-col xl:flex-row gap-4 xl:items-center justify-between">
          <div className="flex items-center gap-2 flex-wrap">
            <div className="flex items-center gap-2 text-xs font-medium text-muted-foreground uppercase tracking-wider mr-2 flex-shrink-0">
              <Filter size={12} />
              Filtros
            </div>
            {filtrosProduto.slice(1).map((filtro) => (
              <CustomSelect
                key={filtro.id}
                options={filtro.opcoes}
                value={filtro.valor}
                onChange={filtro.aplicar}
                className="w-[145px]"
              />
            ))}
            <div ref={actionsRef} className="flex items-center gap-2 pl-2 border-l border-[var(--ks-color-border-subtle)] flex-shrink-0 relative">
              <button
                type="button"
                onClick={() => setActionsOpen(!actionsOpen)}
                className="h-8 w-8 flex items-center justify-center rounded-md hover:bg-gray-100 transition-colors"
                title="Ações em massa"
              >
                <Trash2 size={16} className="text-gray-600 hover:text-red-600" />
              </button>
              {actionsOpen && (
                 <div className="absolute right-0 top-full mt-2 w-48 bg-white rounded-md shadow-lg border border-gray-200 z-50 p-1 flex flex-col gap-1">
                    <button
                      type="button"
                      onClick={(e) => { e.preventDefault(); toggleSelectAll(); }}
                      className="w-full text-left px-3 py-2 text-sm hover:bg-gray-100 rounded-sm flex items-center gap-2 transition-colors"
                    >
                       <CheckSquare size={14} className="text-muted-foreground" />
                       {selectedProducts.size === products.length ? "Deselecionar Todos" : "Selecionar Todos"}
                    </button>
                     {podeMexerEmProdutos && (
                     <button
                      type="button"
                      onClick={() => { if(selectedProducts.size > 0) { handleBulkDelete(); setActionsOpen(false); } }}
                      disabled={selectedProducts.size === 0}
                      className="w-full text-left px-3 py-2 text-sm hover:bg-red-50 text-red-600 rounded-sm flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                    >
                       <Trash2 size={14} />
                       Excluir ({selectedProducts.size})
                    </button>
                     )}
                 </div>
              )}
            </div>
          </div>

          <div className="flex items-center gap-4 text-xs font-medium text-muted-foreground xl:border-l xl:pl-4 flex-shrink-0">
            <div className="flex items-center gap-1.5">
               <span className="w-1.5 h-1.5 rounded-full bg-slate-400" />
               <span className="text-foreground">{totaisProdutos.total}</span> Total
            </div>
            <div className="flex items-center gap-1.5">
               <span className="w-1.5 h-1.5 rounded-full bg-emerald-500" />
               <span className="text-foreground">{totaisProdutos.comFoto}</span> Com foto
            </div>
            <div className="flex items-center gap-1.5">
               <span className="w-1.5 h-1.5 rounded-full bg-rose-500" />
               <span className="text-foreground">{totaisProdutos.esgotados}</span> Esgotados
            </div>
          </div>
        </div>

        {/* Totais do celular: uma faixa fina, sem os pontos coloridos brigando
            por espaco com o texto */}
        <div className="md:hidden flex items-center justify-between gap-2 border-t border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-subtle)]/50 px-3 py-2 text-[11px] font-medium text-muted-foreground rounded-b-xl">
          <span className="flex items-center gap-1">
            <span className="h-1.5 w-1.5 rounded-full bg-slate-400" />
            <span className="text-foreground font-semibold">{totaisProdutos.total}</span> Total
          </span>
          <span className="flex items-center gap-1">
            <span className="h-1.5 w-1.5 rounded-full bg-emerald-500" />
            <span className="text-foreground font-semibold">{totaisProdutos.comFoto}</span> Com foto
          </span>
          <span className="flex items-center gap-1">
            <span className="h-1.5 w-1.5 rounded-full bg-rose-500" />
            <span className="text-foreground font-semibold">{totaisProdutos.esgotados}</span> Esgotados
          </span>
        </div>
      </div>



      <AnimatePresence mode="wait" initial={false}>
        {viewMode === "cards" ? (
          <motion.div
            key="cards"
            initial={{ opacity: 0, y: 8 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -8 }}
            transition={{ duration: 0.2 }}
            className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"
          >
            <AnimatePresence mode="popLayout">
              {filteredProducts.map((product) => (
                <motion.div
                  key={product.id}
                  initial={{ opacity: 0, y: 10 }}
                  animate={{ opacity: 1, y: 0 }}
                  className="bg-white rounded-2xl border border-gray-100 p-4 hover:border-gray-300 hover:shadow-sm transition-all duration-200 flex flex-col h-full relative group"
                >
                  <div className="absolute top-3 left-3 z-10">
                    <Checkbox
                      checked={selectedProducts.has(product.id)}
                      onCheckedChange={() => toggleProductSelection(product.id)}
                      className="h-4 w-4 border-gray-300 data-[state=checked]:bg-blue-600 data-[state=checked]:border-blue-600 rounded bg-white/80 backdrop-blur"
                    />
                  </div>
                  <div 
                    className="relative w-full aspect-[4/3] rounded-xl overflow-hidden bg-muted border border-gray-100 mb-4 cursor-pointer"
                    onClick={() => setPreviewProductId(product.id)}
                  >
                    <ProductImageHover product={product} />
                  </div>
                  <div className="min-w-0 flex-1 flex flex-col">
                    <h3 className="font-semibold text-base text-gray-900 truncate mb-1">{product.name}</h3>
                    <p className="text-lg font-bold text-gray-900 mb-2">
                      R$ {(typeof product.price === "number" ? product.price : 0).toFixed(2)}
                    </p>
                    <div className="flex flex-col gap-1 mt-auto text-[13px] text-slate-500 font-medium leading-snug">
                      <div className="flex items-center gap-1.5">
                        {estoqueNovo.v2 && estoqueDaLista[product.id] ? (
                          <EstoqueNaLista info={estoqueDaLista[product.id]} />
                        ) : (product as { track_inventory?: boolean }).track_inventory === true ? (
                          <>
                            <span className={`w-1.5 h-1.5 rounded-full ${(product.stock || 0) > 0 ? "bg-emerald-500" : "bg-rose-500"}`} />
                            <span>Estoque: {product.stock || 0}</span>
                          </>
                        ) : (
                          <>
                            <span className="w-1.5 h-1.5 rounded-full bg-slate-300" />
                            <span>Sob demanda</span>
                          </>
                        )}
                      </div>
                      {product.sku && (
                        <div className="flex items-center mt-1">
                          <span className="text-slate-700 bg-amber-100/80 px-1.5 py-0.5 rounded text-[11px] font-bold tracking-wide truncate">
                            SKU: {product.sku}
                          </span>
                        </div>
                      )}
                      {product.barcode && (
                        <div className="mt-1 opacity-70 mix-blend-multiply scale-90 origin-left">
                          <Barcode 
                            value={product.barcode} 
                            width={1.2} 
                            height={24} 
                            fontSize={10} 
                            margin={0} 
                            displayValue={true} 
                          />
                        </div>
                      )}
                    </div>
                  </div>
                  
                  <div className="mt-4 flex items-center justify-between gap-2 border-t border-gray-100 pt-4">
                    <Link href={`/dashboard/products/${product.id}`} className="flex-1">
                      <button className="w-full h-9 bg-indigo-50 hover:bg-indigo-100 text-indigo-700 font-semibold text-sm rounded-xl flex items-center justify-center gap-2 transition-colors">
                        {podeMexerEmProdutos ? <Edit className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
                        {podeMexerEmProdutos ? "Editar" : "Ver"}
                      </button>
                    </Link>
                    <div className="flex items-center gap-2">
                      {podeMexerEmProdutos ? <button
                        onClick={() => handleDuplicateProduct(product.id)}
                        disabled={duplicatingProductId === product.id}
                        title="Duplicar"
                        className="w-9 h-9 flex items-center justify-center rounded-xl border border-gray-200 bg-white text-gray-600 hover:bg-gray-50 hover:text-indigo-600 transition-colors disabled:opacity-50"
                      >
                        {duplicatingProductId === product.id ? <Loader2 className="h-4 w-4 animate-spin" /> : <Copy className="h-4 w-4" />}
                      </button> : null}
                      {podeMexerEmProdutos ? <button
                        onClick={() => handleSingleDelete(product.id)}title="Excluir"
                        className="w-9 h-9 flex items-center justify-center rounded-xl border border-gray-200 bg-white text-gray-600 hover:bg-red-50 hover:border-red-200 hover:text-red-600 transition-colors"
                      >
                        <Trash2 className="h-4 w-4" />
                      </button> : null}
                    </div>
                  </div>
                </motion.div>
              ))}
            </AnimatePresence>
          </motion.div>
        ) : (
          <motion.div
            key="list"
            initial={{ opacity: 0, y: 8 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -8 }}
            transition={{ duration: 0.2 }}
            className="flex flex-col gap-3"
          >
            {filteredProducts.map((product) => (
              <div 
                key={product.id} 
                className="group bg-white rounded-2xl p-4 border border-gray-100 hover:border-gray-300 hover:shadow-sm transition-all duration-200 flex flex-col md:flex-row items-center gap-4 relative"
              >
                <div className="flex items-center gap-4 flex-1 min-w-[240px]">
                  <Checkbox
                    checked={selectedProducts.has(product.id)}
                    onCheckedChange={() => toggleProductSelection(product.id)}
                    className="h-4 w-4 border-gray-300 data-[state=checked]:bg-blue-600 data-[state=checked]:border-blue-600"
                  />
                  <div 
                    className="w-12 h-12 rounded-xl overflow-hidden bg-muted flex-shrink-0 relative border border-gray-100 cursor-pointer"
                    onClick={() => setPreviewProductId(product.id)}
                  >
                    <ProductImageHover product={product} />
                  </div>
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center gap-2 mb-0.5">
                      <span className="font-semibold text-gray-900 truncate">{product.name}</span>
                      {product.catalog_color ? (
                        <span
                          className="inline-block w-3 h-3 rounded-full border border-gray-200 shadow-sm"
                          style={{ backgroundColor: product.catalog_color || "#ffffff" }}
                        />
                      ) : null}
                    </div>
                    <div className="flex items-center gap-3 text-xs text-gray-500 font-medium truncate">
                      <span className="text-gray-900 font-bold text-sm">
                        R$ {(typeof product.price === "number" ? product.price : 0).toFixed(2)}
                      </span>
                      <div className="flex items-center gap-1.5">
                        {estoqueNovo.v2 && estoqueDaLista[product.id] ? (
                          <EstoqueNaLista info={estoqueDaLista[product.id]} />
                        ) : (product as { track_inventory?: boolean }).track_inventory === true ? (
                          <>
                            <span className={`w-1.5 h-1.5 rounded-full ${(product.stock || 0) > 0 ? "bg-emerald-500" : "bg-rose-500"}`} />
                            <span>Estoque: {product.stock || 0}</span>
                          </>
                        ) : (
                          <>
                            <span className="w-1.5 h-1.5 rounded-full bg-slate-300" />
                            <span>Sob demanda</span>
                          </>
                        )}
                      </div>
                      {product.sku && (
                        <div className="flex items-center pl-3 border-l border-gray-200">
                          <span className="text-slate-700 bg-amber-100/80 px-1.5 py-0.5 rounded text-[11px] font-bold tracking-wide truncate" title={`SKU: ${product.sku}`}>
                            SKU: {product.sku}
                          </span>
                        </div>
                      )}
                      {product.barcode && (
                        <div className="border-l border-gray-200 pl-3 flex items-center h-[20px] overflow-hidden opacity-70 mix-blend-multiply">
                          <Barcode 
                            value={product.barcode} 
                            width={1} 
                            height={20} 
                            fontSize={0} 
                            margin={0} 
                            displayValue={false} 
                          />
                        </div>
                      )}
                    </div>
                  </div>
                </div>

                <div className="flex items-center gap-2 mt-3 md:mt-0 w-full md:w-auto border-t md:border-t-0 border-gray-100 pt-3 md:pt-0">
                  <Link href={`/dashboard/products/${product.id}`} className="flex-1 md:flex-none">
                    <button className="w-full md:w-auto px-4 h-9 bg-indigo-50 hover:bg-indigo-100 text-indigo-700 font-semibold text-sm rounded-xl flex items-center justify-center gap-2 transition-colors whitespace-nowrap">
                      <Edit className="h-4 w-4" />
                      Editar
                    </button>
                  </Link>
                  <div className="flex items-center gap-2">
                    {podeMexerEmProdutos ? <button
                        onClick={() => handleDuplicateProduct(product.id)}
                      disabled={duplicatingProductId === product.id}
                      title="Duplicar"
                      className="w-9 h-9 flex items-center justify-center rounded-xl border border-gray-200 bg-white text-gray-600 hover:bg-gray-50 hover:text-indigo-600 transition-colors disabled:opacity-50"
                    >
                      {duplicatingProductId === product.id ? <Loader2 className="h-4 w-4 animate-spin" /> : <Copy className="h-4 w-4" />}
                    </button> : null}
                    {podeMexerEmProdutos ? <button
                        onClick={() => handleSingleDelete(product.id)}title="Excluir"
                      className="w-9 h-9 flex items-center justify-center rounded-xl border border-gray-200 bg-white text-gray-600 hover:bg-red-50 hover:border-red-200 hover:text-red-600 transition-colors"
                    >
                      <Trash2 className="h-4 w-4" />
                    </button> : null}
                  </div>
                </div>
              </div>
            ))}
          </motion.div>
        )}
      </AnimatePresence>

        {filteredProducts.length === 0 && (
          <div className="text-center py-12">
            <Package className="h-12 w-12 text-muted-foreground mx-auto mb-4" />
            <h3 className="text-lg font-medium">Nenhum produto encontrado</h3>
            <p className="text-muted-foreground">
              {searchTerm
                ? "Tente ajustar seus termos de busca"
                : "Comece adicionando seu primeiro produto"}
            </p>
          </div>
        )}
      

      {/* Modal de confirmação de exclusão com vínculos */}
      <Dialog open={isDeleteDialogOpen} onOpenChange={setIsDeleteDialogOpen}>
        <DialogContent
          className="max-w-3xl max-h-[85vh] flex flex-col"
          onInteractOutside={(event) => event.preventDefault()}
          onEscapeKeyDown={(event) => event.preventDefault()}
        >
          <DialogHeader>
            <DialogTitle>Confirmar Exclusão</DialogTitle>
            <DialogDescription>
              Alguns produtos possuem vínculos com orçamentos ou pedidos. 
              Deseja realmente excluí-los?
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            <Alert variant="destructive">
              <AlertTriangle className="h-4 w-4" />
              <AlertTitle>Atenção!</AlertTitle>
              <AlertDescription>
                Os produtos serão removidos do catálogo, mas permanecerão 
                nos orçamentos e pedidos existentes.
              </AlertDescription>
            </Alert>

            <div className="max-h-60 overflow-y-auto min-h-0">
              <h4 className="font-medium mb-2">Produtos com vínculos:</h4>
              <ul className="space-y-2">
                {deleteStatus.linkedProducts.map((product) => (
                  <li key={product.id} className="text-sm p-2 bg-muted rounded">
                    <div className="font-medium">{product.name}</div>
                    <div className="text-muted-foreground">
                      {product.quoteCount} orçamento(s), {product.orderCount} pedido(s)
                    </div>
                  </li>
                ))}
              </ul>
            </div>
          </div>

          <DialogFooter className="gap-2 flex-wrap sm:flex-nowrap">
            <Button
              variant="secondary"
              onClick={() => setIsDeleteDialogOpen(false)}
            >
              Cancelar
            </Button>
            <Button
              variant="secondary"
              onClick={() => {
                setSelectedProducts(new Set());
                setDeleteStatus({ loading: false, linkedProducts: [], forceDelete: false });
                setIsDeleteDialogOpen(false);
              }}
              disabled={deleteStatus.loading}
            >
              Excluir restantes e manter vinculados
            </Button>
            <Button
              variant="secondary"
              className="bg-red-600 hover:bg-red-700 text-white"
              onClick={handleConfirmDelete}
              disabled={deleteStatus.loading}
            >
              {deleteStatus.loading ? (
                <Loader2 className="h-4 w-4 mr-2 animate-spin" />
              ) : null}
              Excluir mesmo assim
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog
        open={bulkProgress.open}
        onOpenChange={(open) => {
          if (!open && !bulkProgress.finished) return;
          setBulkProgress((prev) => ({ ...prev, open }));
        }}
      >
        <DialogContent
          onInteractOutside={(event) => {
            if (!bulkProgress.finished) event.preventDefault();
          }}
          onEscapeKeyDown={(event) => {
            if (!bulkProgress.finished) event.preventDefault();
          }}
        >
          <DialogHeader>
            <DialogTitle>Exclusão em massa</DialogTitle>
            <DialogDescription>
              {bulkProgress.finished ? "Concluído" : "Excluindo produtos selecionados"}
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            {bulkProgress.finished ? (
              <div className="flex flex-col items-center justify-center gap-3 py-6">
                <div className="h-12 w-12 rounded-full bg-[var(--ks-color-primary)] text-white flex items-center justify-center">
                  <Check className="h-6 w-6" />
                </div>
                <div className="text-sm font-semibold text-[var(--ks-color-text-primary)]">Concluído</div>
              </div>
            ) : (
              <>
                <div className="h-2 w-full rounded-full bg-[var(--ks-color-bg-subtle)] overflow-hidden">
                  <div
                    className="h-full bg-[var(--ks-color-primary)] transition-all"
                    style={{
                      width: bulkProgress.total > 0 ? `${Math.round((bulkProgress.deleted / bulkProgress.total) * 100)}%` : "0%",
                    }}
                  />
                </div>
                <div className="text-sm text-[var(--ks-color-text-muted)]">
                  {bulkProgress.deleted} excluídos de {bulkProgress.total} · faltam{" "}
                  {Math.max(0, bulkProgress.total - bulkProgress.deleted)}
                </div>
              </>
            )}
          </div>

          <DialogFooter>
            <Button
              variant="secondary"
              onClick={() => setBulkProgress((prev) => ({ ...prev, open: false }))}
              disabled={!bulkProgress.finished}
            >
              Fechar
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Modal de importação (mantido da implementação original) */}
      <Dialog open={importOpen} onOpenChange={handleImportOpenChange}>
        <DialogContent
          className="max-w-4xl"
          onInteractOutside={(event) => event.preventDefault()}
        >
          <DialogHeader>
            <DialogTitle>Importar Produtos</DialogTitle>
            <DialogDescription>
              Faça upload de uma planilha Excel para importar produtos em massa.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            <div className="space-y-2">
              <Input
                type="file"
                accept=".xlsx,.xls,.csv"
                onChange={handleImportFileChange}
                disabled={importing}
              />
              {importFileName ? (
                <div className="flex items-center justify-between text-sm text-muted-foreground">
                  <span className="truncate">{importFileName}</span>
                  <Button variant="ghost" size="sm" onClick={handleClearImport} disabled={importing}>
                    Remover
                  </Button>
                </div>
              ) : null}
            </div>

            {importing ? (
              <div className="space-y-2 rounded-md border p-3">
                <div className="flex items-center justify-between text-sm">
                  <span className="text-[var(--ks-color-text-primary)]">
                    {importProgress.cancelRequested ? "Cancelando importação..." : "Importando produtos..."}
                  </span>
                  <span className="text-[var(--ks-color-text-muted)]">
                    {importProgress.processed} / {importProgress.total}
                  </span>
                </div>
                <div className="h-2 w-full rounded-full bg-[var(--ks-color-bg-subtle)] overflow-hidden">
                  <div
                    className="h-full bg-[var(--ks-color-primary)] transition-all"
                    style={{
                      width:
                        importProgress.total > 0
                          ? `${Math.round((importProgress.processed / importProgress.total) * 100)}%`
                          : "0%",
                    }}
                  />
                </div>
                <div className="text-xs text-[var(--ks-color-text-muted)]">
                  {importProgress.created} produto(s) criado(s)
                </div>
              </div>
            ) : null}

            {importPreview && (
              <div className="space-y-2">
                <div className="text-sm text-muted-foreground">
                  {importPreview.rows.length} linha(s) encontradas
                </div>
                <div className="rounded-md border p-3 space-y-2">
                  <div className="text-xs font-medium text-[var(--ks-color-text-primary)]">Mapeamento detectado</div>
                  <div className="grid grid-cols-1 sm:grid-cols-2 gap-2 text-xs">
                    {(["nome", "preco", "estoque", "ativo", "descricao", "categoria", "sku"] as const).map((field) => {
                      const mappedHeader = getMappedHeaderName(importPreview, field);
                      return (
                        <div key={field} className="flex items-center gap-2">
                          <span className="text-[var(--ks-color-text-muted)] min-w-[72px]">{standardFieldLabels[field]}:</span>
                          <span className={mappedHeader ? "text-[var(--ks-color-text-primary)]" : "text-[var(--ks-color-text-muted)]"}>
                            {mappedHeader || "não detectado"}
                          </span>
                        </div>
                      );
                    })}
                  </div>
                </div>
                <div className="rounded-md border overflow-hidden">
                  <div className="max-h-56 overflow-y-auto">
                    <table className="w-full text-sm">
                      <thead className="bg-muted">
                        <tr>
                          <th className="text-left px-3 py-2 font-medium">Nome</th>
                          <th className="text-left px-3 py-2 font-medium">Preço</th>
                          <th className="text-left px-3 py-2 font-medium">Estoque</th>
                          <th className="text-left px-3 py-2 font-medium">Ativo</th>
                        </tr>
                      </thead>
                      <tbody>
                        {importPreview.rows.slice(0, 8).map((row) => (
                          <tr key={`${row.rowNumber}-${row.name}`}>
                            <td className="px-3 py-2">{row.name || "-"}</td>
                            <td className="px-3 py-2">
                              {row.priceOnRequest
                                ? "Sob consulta"
                                : row.price !== null
                                ? `R$ ${row.price.toFixed(2)}`
                                : "-"}
                            </td>
                            <td className="px-3 py-2">{row.stock ?? "-"}</td>
                            <td className="px-3 py-2">{row.active ? "Sim" : "Não"}</td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>
                  {importPreview.rows.length > 8 && (
                    <div className="px-3 py-2 text-xs text-muted-foreground">
                      Mostrando 8 de {importPreview.rows.length} linhas
                    </div>
                  )}
                </div>
              </div>
            )}

            {importResult && (
              <Alert variant={importResult.errors.length ? "destructive" : "default"}>
                <AlertTitle>Importação concluída</AlertTitle>
                <AlertDescription>
                  <div className="space-y-1">
                    <div>Produtos criados: {importResult.productsCreated}</div>
                    <div>Categorias criadas: {importResult.categoriesCreated}</div>
                    <div>Imagens criadas: {importResult.imagesCreated}</div>
                    <div>Linhas ignoradas: {importResult.skippedRows}</div>
                    {importResult.errors.length > 0 && (
                      <div className="max-h-32 overflow-y-auto text-sm">
                        {importResult.errors.slice(0, 6).map((error, index) => (
                          <div key={`${error.rowNumber}-${index}`}>
                            Linha {error.rowNumber}: {error.message}
                          </div>
                        ))}
                      </div>
                    )}
                  </div>
                </AlertDescription>
              </Alert>
            )}
          </div>

          <DialogFooter>
            <Button
              variant="secondary"
              onClick={() => handleImportOpenChange(false)}
            >
              Fechar
            </Button>
            <Button
              onClick={handleStartImport}
              disabled={!importPreview?.rows.length || importing}
            >
              {importing ? <Loader2 className="h-4 w-4 mr-2 animate-spin" /> : null}
              {importing ? (importProgress.cancelRequested ? "Cancelando..." : "Importando...") : "Importar agora"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={importCancelDialogOpen} onOpenChange={setImportCancelDialogOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Cancelar importação?</DialogTitle>
            <DialogDescription>
              Se cancelar agora, nenhum produto importado será mantido e nada aparecerá na lista.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button
              variant="secondary"
              onClick={() => setImportCancelDialogOpen(false)}
              disabled={importProgress.cancelRequested}
            >
              Continuar importando
            </Button>
            <Button
              variant="secondary"
              className="bg-red-600 hover:bg-red-700 text-white"
              onClick={requestCancelImport}
              disabled={importProgress.cancelRequested}
            >
              {importProgress.cancelRequested ? <Loader2 className="h-4 w-4 mr-2 animate-spin" /> : null}
              Cancelar importação
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
      <ProductPreviewModal 
        productId={previewProductId} 
        onClose={() => setPreviewProductId(null)} 
      />
    </div>
  );
}
