import type { SupabaseClient } from "@supabase/supabase-js";

import { createAdminClient } from "@/lib/supabase-server";

import { arquivoDaFoto } from "./arquivo-da-foto";

export { arquivoDaFoto };

/*
 * Excluir produtos físicos, igual para o painel (lista de produtos, um ou em
 * lote) e para o assistente (MCP).
 *
 * Era o miolo da rota /api/products/bulk-delete. A regra continua a mesma:
 * produto que aparece em orçamento ou pedido só sai com `forceDelete` (a tela
 * pergunta antes; o assistente mostra a prévia). Os itens dos orçamentos e
 * pedidos ficam, só perdem o vínculo com o cadastro (o banco zera o
 * product_id); fotos, variações, faixas, estoque por opção, receitas,
 * serviços e combos saem junto com o produto (cascata do banco).
 *
 * As fotos: a rota antiga procurava o arquivo nas colunas velhas (url, path),
 * vazias nas fotos de hoje, e o arquivo ficava esquecido no depósito. Agora o
 * endereço novo (image_url) também vale — mas o arquivo só é apagado quando
 * nenhuma outra foto ou produto usa o mesmo endereço (o produto duplicado
 * aponta para as mesmas fotos do original).
 */

export type ProdutoComVinculo = { id: string; name: string; quoteCount: number; orderCount: number };

export type ResultadoDaExclusao = {
  results: Array<{ productId: string; success: boolean; error?: string }>;
  deletedCount: number;
  failedCount: number;
  linkedProducts: ProdutoComVinculo[];
};

type FotoGuardada = { url: string | null; path: string | null; image_url: string | null };

/**
 * Apaga do depósito os arquivos destas fotos que mais ninguém usa.
 * `ignorarProdutos`: os produtos que estão saindo (as fotos deles não contam como uso).
 */
export async function apagarArquivosSemUso(
  supabase: SupabaseClient,
  fotos: FotoGuardada[],
  ignorarProdutos: string[]
): Promise<number> {
  const admin = createAdminClient();
  const porDeposito = new Map<string, string[]>();
  for (const foto of fotos) {
    const arquivo = arquivoDaFoto(foto);
    const endereco = foto.image_url || foto.url;
    if (!arquivo || !endereco) continue;
    /* Quem mais aponta para o mesmo endereço? A conferência é pelo banco
       inteiro (chave de serviço), só para contar: nada é lido além do id. */
    let outrasFotos = admin
      .from("product_images")
      .select("id", { count: "exact", head: true })
      .or(`image_url.eq.${JSON.stringify(endereco)},url.eq.${JSON.stringify(endereco)}`);
    let outrosProdutos = admin.from("products").select("id", { count: "exact", head: true }).eq("image_url", endereco);
    if (ignorarProdutos.length) {
      outrasFotos = outrasFotos.not("product_id", "in", `(${ignorarProdutos.join(",")})`);
      outrosProdutos = outrosProdutos.not("id", "in", `(${ignorarProdutos.join(",")})`);
    }
    const [usoEmFotos, usoEmProdutos] = await Promise.all([outrasFotos, outrosProdutos]);
    if (usoEmFotos.error || usoEmProdutos.error) continue;
    if ((usoEmFotos.count ?? 0) > 0 || (usoEmProdutos.count ?? 0) > 0) continue;
    const lista = porDeposito.get(arquivo.bucket) ?? [];
    if (!lista.includes(arquivo.filePath)) lista.push(arquivo.filePath);
    porDeposito.set(arquivo.bucket, lista);
  }
  let apagados = 0;
  for (const [bucket, caminhos] of porDeposito) {
    const { data, error } = await supabase.storage.from(bucket).remove(caminhos);
    if (error) console.error("[produtos] apagar fotos do depósito:", error.message);
    apagados += data?.length ?? 0;
  }
  return apagados;
}

/** Quantos orçamentos e pedidos usam cada produto. */
export async function vinculosDosProdutos(supabase: SupabaseClient, ids: string[]) {
  const [{ data: quoteItems }, { data: orderItems }] = await Promise.all([
    supabase.from("quote_items").select("product_id").in("product_id", ids),
    supabase.from("order_items").select("product_id").in("product_id", ids),
  ]);
  const orcamentos = new Map<string, number>();
  const pedidos = new Map<string, number>();
  for (const item of (quoteItems ?? []) as Array<{ product_id: string | null }>) {
    if (item.product_id) orcamentos.set(item.product_id, (orcamentos.get(item.product_id) || 0) + 1);
  }
  for (const item of (orderItems ?? []) as Array<{ product_id: string | null }>) {
    if (item.product_id) pedidos.set(item.product_id, (pedidos.get(item.product_id) || 0) + 1);
  }
  return { orcamentos, pedidos };
}

export async function excluirProdutosComoOPainel(entrada: {
  supabase: SupabaseClient;
  tenantIds: string[];
  productIds: string[];
  forceDelete: boolean;
}): Promise<{ ok: true; resultado: ResultadoDaExclusao } | { ok: false; status: number; error: string }> {
  const { supabase, tenantIds, productIds, forceDelete } = entrada;

  const { data: products, error: productsError } = await supabase
    .from("products")
    .select("id, name")
    .in("id", productIds)
    .in("user_id", tenantIds)
    .neq("product_kind", "digital");

  if (productsError) return { ok: false, status: 400, error: productsError.message };

  const lista = (products ?? []) as Array<{ id: string; name: string }>;
  const productIdList = lista.map((product) => product.id);
  if (productIdList.length === 0) return { ok: false, status: 404, error: "Produtos não encontrados." };

  const { orcamentos, pedidos } = await vinculosDosProdutos(supabase, productIdList);

  const linkedProducts: ProdutoComVinculo[] = [];
  const unlinkedProducts: string[] = [];
  for (const product of lista) {
    const quoteCount = orcamentos.get(product.id) || 0;
    const orderCount = pedidos.get(product.id) || 0;
    if ((quoteCount > 0 || orderCount > 0) && !forceDelete) {
      linkedProducts.push({ id: product.id, name: product.name, quoteCount, orderCount });
    } else {
      unlinkedProducts.push(product.id);
    }
  }

  const deleteProducts = async (ids: string[]) =>
    Promise.all(
      ids.map(async (productId) => {
        try {
          const { data: images } = await supabase.from("product_images").select("url, path, image_url").eq("product_id", productId);

          await Promise.all([
            supabase.from("product_images").delete().eq("product_id", productId),
            supabase.from("product_variants").delete().eq("product_id", productId),
          ]);

          const { error: deleteError } = await supabase.from("products").delete().eq("id", productId);
          if (deleteError) return { productId, success: false, error: deleteError.message };

          /* Só depois de o produto sair: se a exclusão falhar, as fotos continuam lá. */
          if (images && images.length > 0) {
            await apagarArquivosSemUso(supabase, images as FotoGuardada[], [productId]).catch((erro) =>
              console.error("[produtos] fotos do produto excluído:", erro instanceof Error ? erro.message : erro)
            );
          }
          return { productId, success: true };
        } catch (error) {
          return { productId, success: false, error: error instanceof Error ? error.message : "Erro desconhecido" };
        }
      })
    );

  const resultado = (results: ResultadoDaExclusao["results"], ligados: ProdutoComVinculo[]): ResultadoDaExclusao => ({
    results,
    deletedCount: results.filter((r) => r.success).length,
    failedCount: results.filter((r) => !r.success).length,
    linkedProducts: ligados,
  });

  if (!forceDelete && linkedProducts.length > 0) {
    return { ok: true, resultado: resultado(await deleteProducts(unlinkedProducts), linkedProducts) };
  }
  const productsToDelete = forceDelete ? productIdList : unlinkedProducts;
  return { ok: true, resultado: resultado(await deleteProducts(productsToDelete), forceDelete ? linkedProducts : []) };
}
