import { NextResponse } from "next/server";
import { createClient } from "@/lib/supabase-server";
import { canCompany, getCompanyContext } from "@/lib/company-context";
import { avisarLoja } from "@/lib/loja/avisar-loja";
import { downloadAndUploadImage } from "@/lib/import-images";
import { processProductImages } from "./process-product-images";

export const runtime = "nodejs";

type ImportRow = {
  rowNumber?: number;
  name?: string;
  sku?: string;
  description?: string;
  categoryPath?: string[];
  price?: number | string | null;
  pricePromotional?: number | string | null;
  priceOnRequest?: boolean;
  stock?: number | string | null;
  unitType?: string | null;
  active?: boolean;
  imageUrls?: string[];
  attributes?: Array<{
    name?: string;
    options?: string[];
    allow_multiple?: boolean;
    is_required?: boolean;
    position?: number;
  }>;
  variations?: Array<{
    combination?: Record<string, string>;
    sku?: string | null;
    price?: number | string | null;
    stock?: number | string | null;
    cost_adjustment?: number | string | null;
  }>;
};

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

function slugify(input: string) {
  return input
    .toLowerCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^\w\s-]/g, "")
    .trim()
    .replace(/\s+/g, "-");
}

function parseNumber(value: unknown) {
  if (typeof value === "number" && !Number.isNaN(value)) return value;
  if (typeof value !== "string") return null;
  const normalized = value.replace(/\./g, "").replace(",", ".").replace(/[^\d.-]/g, "");
  const parsed = Number.parseFloat(normalized);
  return Number.isNaN(parsed) ? null : parsed;
}

function parseInteger(value: unknown) {
  const parsed = parseNumber(value);
  if (parsed === null) return null;
  return Math.round(parsed);
}

function normalizeString(value: unknown) {
  return typeof value === "string" ? value.trim() : "";
}

async function getAuth() {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  return { supabase, user };
}

export async function POST(req: Request) {
  const { supabase, user } = await getAuth();
  if (!user) return NextResponse.json({ error: "Não autenticado." }, { status: 401 });

  const body = (await req.json().catch(() => null)) as { rows?: unknown } | null;
  const rowsRaw = Array.isArray(body?.rows) ? (body?.rows as ImportRow[]) : null;
  if (!rowsRaw) return NextResponse.json({ error: "Dados inválidos." }, { status: 400 });

  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "products.catalog.write")) {
    return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
  }

  const canWriteCategories = canCompany(ctx, user.id, "categories.write");
  const writeUserId = ctx.ownerId ?? ctx.companyId;

  const { data: categoriesData, error: categoriesError } = await supabase
    .from("categories")
    .select("id,name,slug")
    .eq("user_id", writeUserId);

  if (categoriesError) {
    return NextResponse.json({ error: categoriesError.message }, { status: 400 });
  }

  const categoriesBySlug = new Map<string, { id: string; name: string; slug: string }>();
  (categoriesData || []).forEach((cat) => {
    if (cat && typeof cat.slug === "string") {
      categoriesBySlug.set(cat.slug, cat as { id: string; name: string; slug: string });
    }
  });

  let productsCreated = 0;
  let variantsCreated = 0;
  let categoriesCreated = 0;
  let imagesCreated = 0;
  let skippedRows = 0;
  const errors: { rowNumber: number; message: string }[] = [];
  const createdProductIds: string[] = [];

  for (let index = 0; index < rowsRaw.length; index += 1) {
    const row = rowsRaw[index] || {};
    const rowNumber = typeof row.rowNumber === "number" ? row.rowNumber : index + 2;
    const name = normalizeString(row.name);
    if (!name) {
      errors.push({ rowNumber, message: "Nome do produto obrigatório." });
      skippedRows += 1;
      continue;
    }

    let priceOnRequest = row.priceOnRequest === true;
    const pricePromotional = parseNumber(row.pricePromotional);
    const priceBase = parseNumber(row.price);
    const price = pricePromotional !== null && pricePromotional > 0 ? pricePromotional : priceBase;

    if (!priceOnRequest && (price === null || price <= 0 || Number.isNaN(price))) {
      priceOnRequest = true;
    }

    const stockRaw = parseInteger(row.stock);
    if (stockRaw !== null && stockRaw < 0) {
      errors.push({ rowNumber, message: "Estoque inválido." });
      skippedRows += 1;
      continue;
    }

    const categorySegments = Array.isArray(row.categoryPath)
      ? row.categoryPath.map((part) => normalizeString(part)).filter(Boolean)
      : [];
    let categoryId: string | null = null;
    if (categorySegments.length) {
      const categoryName = categorySegments.join(" > ");
      const categorySlug = slugify(categoryName);
      if (categorySlug) {
        const existing = categoriesBySlug.get(categorySlug);
        if (existing) {
          categoryId = existing.id;
        } else if (canWriteCategories) {
          const { data: createdCategory, error: createError } = await supabase
            .from("categories")
            .insert({ user_id: writeUserId, name: categoryName, slug: categorySlug })
            .select("id,name,slug")
            .single();
          if (createError) {
            const code =
              typeof createError === "object" && createError !== null && "code" in createError
                ? (createError as { code?: string }).code
                : undefined;
            if (code === "23505") {
              const { data: existingCategory } = await supabase
                .from("categories")
                .select("id,name,slug")
                .eq("user_id", writeUserId)
                .eq("slug", categorySlug)
                .maybeSingle();
              if (existingCategory) {
                categoriesBySlug.set(categorySlug, existingCategory as { id: string; name: string; slug: string });
                categoryId = (existingCategory as { id: string }).id;
              } else {
                errors.push({ rowNumber, message: "Falha ao criar categoria." });
                skippedRows += 1;
                continue;
              }
            } else {
              errors.push({ rowNumber, message: "Falha ao criar categoria." });
              skippedRows += 1;
              continue;
            }
          } else if (createdCategory) {
            categoriesBySlug.set(categorySlug, createdCategory as { id: string; name: string; slug: string });
            categoryId = (createdCategory as { id: string }).id;
            categoriesCreated += 1;
          }
        } else {
          errors.push({ rowNumber, message: "Sem permissão para criar categoria." });
          skippedRows += 1;
          continue;
        }
      }
    }

    const resolvedPrice = priceOnRequest ? 0 : (price ?? 0);
    const payload = {
      user_id: writeUserId,
      name,
      description: normalizeString(row.description) || null,
      price: resolvedPrice,
      price_on_request: priceOnRequest,
      stock: stockRaw ?? 0,
      unit_type: normalizeString(row.unitType) || null,
      category_id: categoryId,
      image_url: null,
      active: typeof row.active === "boolean" ? row.active : true,
      show_in_catalog: false,
      is_catalog_exclusive: false,
    };

    const { data: inserted, error: insertError } = await supabase
      .from("products")
      .insert(payload)
      .select("id")
      .single();
    if (insertError || !inserted?.id) {
      errors.push({ rowNumber, message: insertError?.message || "Falha ao importar produto." });
      skippedRows += 1;
      continue;
    }

    productsCreated += 1;
    createdProductIds.push(inserted.id);

    const rawAttributes = Array.isArray(row.attributes) ? row.attributes : [];
    /* Coluna fiscal/de sistema de planilha exportada (NCM, peso, custo,
       fornecedor…) não é variação de venda — importada como atributo, ela
       vira opção de escolha no catálogo e só polui. */
    const COLUNA_DE_PLANILHA =
      /^(ncm(_\d+)?|cest|ean|gtin|cfop|icms|peso(_liq|_bruto)?|estoque(_minimo|_maximo)?|valor_custo|custo|id_fornecedor|fornecedor|origem(_.*)?|marca_\d+|tipo_class_fiscal|class_fiscal|tipo_produto_servico|produto_variado(_.*)?)$/i;
    const normalizedAttributes = rawAttributes
      .map((attribute) => {
        const nameValue = normalizeString(attribute?.name);
        const optionsValue = Array.isArray(attribute?.options)
          ? attribute.options.map((option) => normalizeString(option)).filter(Boolean)
          : [];
        return {
          name: nameValue,
          options: Array.from(new Set(optionsValue)),
          allow_multiple: attribute?.allow_multiple === true,
          is_required: attribute?.is_required === true,
          position: Number.isFinite(Number(attribute?.position)) ? Number(attribute?.position) : null,
        };
      })
      .filter((attribute) => attribute.name && attribute.options.length > 0)
      .filter((attribute) => !COLUNA_DE_PLANILHA.test(attribute.name.trim().toLowerCase().replace(/\s+/g, "_")));

    if (normalizedAttributes.length > 0) {
      const attrsPayloadBase = normalizedAttributes.map((attribute) => ({
        product_id: inserted.id,
        name: attribute.name,
        options: attribute.options,
        position: attribute.position,
      }));
      const attrsPayload = normalizedAttributes.map((attribute, index) => ({
        ...attrsPayloadBase[index],
        allow_multiple: attribute.allow_multiple,
        is_required: attribute.is_required,
      }));
      const { error: attrError } = await supabase.from("product_attributes").insert(attrsPayload);
      if (attrError) {
        if (
          attrError.message.includes("allow_multiple") ||
          attrError.message.includes("is_required") ||
          attrError.message.includes("position")
        ) {
          const fallbackPayload = attrsPayloadBase.map((item) => {
            const { position: droppedPosition, ...rest } = item;
            void droppedPosition;
            return rest;
          });
          const { error: fallbackError } = await supabase.from("product_attributes").insert(fallbackPayload);
          if (fallbackError) {
            errors.push({ rowNumber, message: fallbackError.message || "Falha ao importar atributos." });
          }
        } else {
          errors.push({ rowNumber, message: attrError.message || "Falha ao importar atributos." });
        }
      }
    }

    const rawVariations = Array.isArray(row.variations) ? row.variations : [];
    const normalizedVariations = rawVariations
      .map((variation) => {
        const rawCombination = variation?.combination && typeof variation.combination === "object"
          ? variation.combination
          : {};
        const normalizedCombination = Object.entries(rawCombination).reduce((acc, [key, value]) => {
          const normalizedKey = normalizeString(key);
          const normalizedValue = normalizeString(value);
          if (!normalizedKey || !normalizedValue) return acc;
          acc[normalizedKey] = normalizedValue;
          return acc;
        }, {} as Record<string, string>);
        const parsedVariationPrice = parseNumber(variation?.price);
        const parsedVariationStock = parseInteger(variation?.stock);
        return {
          combination: normalizedCombination,
          sku: normalizeString(variation?.sku) || null,
          price: parsedVariationPrice ?? 0,
          stock: parsedVariationStock ?? 0,
          cost_adjustment: parseNumber(variation?.cost_adjustment) ?? 0,
        };
      })
      .filter((variation) => Object.keys(variation.combination).length > 0);

    if (normalizedVariations.length > 0) {
      const varsPayload = normalizedVariations.map((variation) => ({
        product_id: inserted.id,
        combination: variation.combination,
        sku: variation.sku,
        price: variation.price,
        stock: variation.stock,
        cost_adjustment: variation.cost_adjustment,
      }));
      const { error: variationError } = await supabase.from("product_variations").insert(varsPayload);
      if (variationError) {
        errors.push({ rowNumber, message: variationError.message || "Falha ao importar variações." });
      } else {
        variantsCreated += normalizedVariations.length;
      }
    }

    const imageUrls = Array.isArray(row.imageUrls) ? row.imageUrls : [];
    if (imageUrls.length) {
      const result = await processProductImages({
        rowNumber,
        imageUrls,
        tenantId: writeUserId,
        productId: inserted.id,
        upload: downloadAndUploadImage,
        persist: {
          insert: async (rows) => {
            const { error } = await supabase.from("product_images").insert(rows);
            return { error };
          },
          updateProduct: async (productId, url) => {
            const { error } = await supabase.from("products").update({ image_url: url }).eq("id", productId);
            return { error };
          },
        },
      });
      imagesCreated += result.imagesCreated;
      errors.push(...result.errors);
    }
  }

  const result: ImportResult = {
    productsCreated,
    variantsCreated,
    categoriesCreated,
    imagesCreated,
    skippedRows,
    errors,
    createdProductIds,
  };

  avisarLoja(writeUserId, req);
  return NextResponse.json(result);
}
