import { resolveSaleQuantityLimits, sortProductPriceTiers, type ProductPriceTier } from "@/lib/price-tiers";

import { AVISO_DE_DADOS, UNIDADE, contagem, dinheiro, exigir, falha, limparBusca, pode, recusar, texto, um } from "./comum";
import { atributosOrdenados, comoOPrecoSeForma, listaDeEscolhas, type AtributoDoCadastro, type ProdutoDoOrcamento } from "./conta-do-orcamento";
import type { FerramentaDeLeitura } from "./tipos";

type Categoria = { id?: string | null; name?: string | null };

type ProdutoDaLista = {
  id: string;
  name: string | null;
  price: number | null;
  unit_type: string | null;
  active: boolean | null;
  price_on_request: boolean | null;
  stock: number | null;
  track_inventory: boolean | null;
  sku: string | null;
  categories?: Categoria | Categoria[] | null;
};

function linhaDoProduto(row: ProdutoDaLista) {
  const categoria = um(row.categories);
  return {
    id: row.id,
    nome: row.name ?? "",
    preco: row.price_on_request ? null : dinheiro(row.price),
    sob_consulta: Boolean(row.price_on_request),
    vendido_por: UNIDADE[row.unit_type || "unit"] ?? "unidade",
    ativo: row.active !== false,
    categoria: categoria?.name ?? null,
    codigo: row.sku || null,
    ...(row.track_inventory ? { estoque: Number(row.stock ?? 0) } : {}),
  };
}

export const buscarProdutos: FerramentaDeLeitura = {
  nome: "buscar_produtos",
  titulo: "Buscar produtos",
  descricao:
    "Procura produtos do cadastro pelo nome e devolve id, preço, unidade de venda e categoria. Use antes de montar um orçamento, para pegar o id e o preço certos. Sem busca, lista os produtos em ordem alfabética.",
  campos: {
    busca: { tipo: "texto", descricao: "Parte do nome do produto. Ex.: caneca, cartão de visita.", max: 80 },
    categoria_id: { tipo: "id", descricao: "Id de uma categoria, para ver só os produtos dela." },
    situacao: { tipo: "opcao", descricao: "Quais mostrar. O padrão é ativos.", opcoes: ["ativos", "inativos", "todos"] },
    pagina: { tipo: "inteiro", descricao: "Página da lista, começando em 1.", min: 1, max: 500 },
    por_pagina: { tipo: "inteiro", descricao: "Quantos por página. O padrão é 20.", min: 1, max: 50 },
  },
  tipo: "leitura",
  permissoes: ["products.catalog.read"],
  async executar(ctx, args) {
    exigir(ctx, "products.catalog.read", "ver os produtos");
    const busca = limparBusca(args.busca);
    const situacao = (args.situacao as string | undefined) ?? "ativos";
    const pagina = (args.pagina as number | undefined) ?? 1;
    const porPagina = (args.por_pagina as number | undefined) ?? 20;
    const de = (pagina - 1) * porPagina;

    let consulta = ctx.supabase
      .from("products")
      .select("id,name,price,unit_type,active,price_on_request,stock,track_inventory,sku,categories(id,name)", { count: "exact" })
      .in("user_id", ctx.tenantIds)
      .neq("product_kind", "digital")
      .order("name")
      .range(de, de + porPagina - 1);
    if (busca) consulta = consulta.ilike("name", `%${busca}%`);
    if (args.categoria_id) consulta = consulta.eq("category_id", String(args.categoria_id));
    if (situacao === "ativos") consulta = consulta.eq("active", true);
    if (situacao === "inativos") consulta = consulta.eq("active", false);

    const { data, error, count } = await consulta;
    if (error) falha("buscar os produtos", error);
    const produtos = ((data ?? []) as unknown as ProdutoDaLista[]).map(linhaDoProduto);

    return {
      dados: {
        _observacao: AVISO_DE_DADOS,
        produtos,
        total_encontrado: count ?? produtos.length,
        pagina,
        por_pagina: porPagina,
        ...(count && count > de + produtos.length ? { tem_mais: true } : {}),
      },
      resumo: busca
        ? `Buscou produtos por "${busca}" (${contagem(count ?? produtos.length, "encontrado", "encontrados")})`
        : `Listou produtos (${count ?? produtos.length} no cadastro)`,
    };
  },
};

type ProdutoCompleto = ProdutoDaLista & {
  description: string | null;
  cost_total: number | null;
  show_in_catalog: boolean | null;
  inventory_scope: string | null;
  min_sale_qty_enabled: boolean | null;
  min_sale_qty: number | null;
  max_sale_qty_enabled: boolean | null;
  max_sale_qty: number | null;
  allowed_sale_qty_enabled: boolean | null;
  allowed_sale_quantities: number[] | null;
  production_time_value: number | null;
  production_time_unit: string | null;
  use_variation_price_only?: boolean | null;
  product_attributes?: AtributoDoCadastro[] | null;
  product_price_tiers?: ProductPriceTier[] | null;
};

export const verProduto: FerramentaDeLeitura = {
  nome: "ver_produto",
  titulo: "Ver um produto",
  descricao:
    "Mostra um produto por inteiro: descrição, preço, as opções (atributos) e como o preço se forma, faixas de preço por quantidade, quantidade mínima e máxima de venda, prazo de produção, estoque e, para quem pode ver, o custo.",
  campos: {
    produto_id: { tipo: "id", descricao: "Id do produto, devolvido por buscar_produtos.", obrigatorio: true },
  },
  tipo: "leitura",
  permissoes: ["products.catalog.read"],
  async executar(ctx, args) {
    exigir(ctx, "products.catalog.read", "ver os produtos");
    const { data, error } = await ctx.supabase
      .from("products")
      .select(
        "id,name,description,price,unit_type,active,price_on_request,stock,track_inventory,inventory_scope,sku,cost_total,show_in_catalog,min_sale_qty_enabled,min_sale_qty,max_sale_qty_enabled,max_sale_qty,allowed_sale_qty_enabled,allowed_sale_quantities,production_time_value,production_time_unit,use_variation_price_only,product_attributes(name,allow_multiple,is_required,position,options),categories(id,name),product_price_tiers(min_qty,max_qty,unit_price,sort_order,active)"
      )
      .eq("id", String(args.produto_id))
      .in("user_id", ctx.tenantIds)
      .maybeSingle();
    if (error) falha("ler o produto", error);
    if (!data) recusar("Produto não encontrado. Use buscar_produtos para achar o id certo.");

    const produto = data as unknown as ProdutoCompleto;
    const limites = resolveSaleQuantityLimits(produto);
    const faixas = sortProductPriceTiers((produto.product_price_tiers ?? []).filter((faixa) => faixa.active !== false)).map((faixa) => ({
      de: Number(faixa.min_qty),
      ate: faixa.max_qty === null ? null : Number(faixa.max_qty),
      preco_unitario: dinheiro(faixa.unit_price),
    }));
    const prazo = Number(produto.production_time_value ?? 0);
    const unidadeDoPrazo = produto.production_time_unit === "hours" ? "hora(s)" : produto.production_time_unit === "days" ? "dia(s)" : "dia(s) útil(eis)";

    return {
      dados: {
        _observacao: AVISO_DE_DADOS,
        produto: {
          ...linhaDoProduto(produto),
          descricao: texto(produto.description, 1500),
          aparece_na_loja: produto.show_in_catalog !== false,
          faixas_de_preco: faixas,
          quantidade_minima: limites.minQty,
          quantidade_maxima: limites.maxQty,
          quantidades_permitidas: limites.allowedQuantities.length ? limites.allowedQuantities : null,
          prazo_de_producao: prazo > 0 ? `${prazo} ${unidadeDoPrazo}` : null,
          /* As opções (atributos) e como o preço se forma: muitos produtos têm
             preço zero e o valor vem das opções. O detalhe está em ver_opcoes_do_produto. */
          ...(atributosOrdenados(produto).length
            ? {
                opcoes: listaDeEscolhas(produto as unknown as ProdutoDoOrcamento),
                como_o_preco_se_forma: comoOPrecoSeForma(produto as unknown as ProdutoDoOrcamento),
                para_orcar: "Use ver_opcoes_do_produto para ver cada opção (com o id) e calcular_preco para conferir o valor.",
              }
            : {}),
          ...(produto.track_inventory && produto.inventory_scope && produto.inventory_scope !== "product"
            ? { estoque_por_variacao: "O estoque deste produto é controlado por variação. Veja o detalhe no painel." }
            : {}),
          /* O custo é do miolo do negócio: só para quem já vê a precificação. */
          ...(pode(ctx, "pricing.config.read") ? { custo: dinheiro(produto.cost_total) } : {}),
        },
      },
      resumo: `Consultou o produto ${produto.name ?? ""}`.trim(),
    };
  },
};

export const listarCategorias: FerramentaDeLeitura = {
  nome: "listar_categorias",
  titulo: "Listar categorias de produto",
  descricao: "Lista as categorias de produto da empresa, com o id de cada uma. Use para filtrar buscar_produtos por categoria.",
  campos: {},
  tipo: "leitura",
  permissoes: ["categories.read"],
  async executar(ctx) {
    exigir(ctx, "categories.read", "ver as categorias");
    const { data, error } = await ctx.supabase
      .from("categories")
      .select("id,name,parent_id,is_visible")
      .in("user_id", ctx.tenantIds)
      .order("name")
      .limit(500);
    if (error) falha("listar as categorias", error);
    const linhas = (data ?? []) as Array<{ id: string; name: string | null; parent_id: string | null; is_visible: boolean | null }>;
    const nomes = new Map(linhas.map((linha) => [linha.id, linha.name ?? ""]));
    return {
      dados: {
        _observacao: AVISO_DE_DADOS,
        categorias: linhas.map((linha) => ({
          id: linha.id,
          nome: linha.name ?? "",
          dentro_de: linha.parent_id ? nomes.get(linha.parent_id) ?? null : null,
          aparece_na_loja: linha.is_visible !== false,
        })),
      },
      resumo: `Listou as categorias (${linhas.length})`,
    };
  },
};
