"use client";

import { useState } from "react";
import Image from "next/image";
import { Check, Loader2, Minus, Plus } from "lucide-react";
import { toast } from "sonner";
import ComboConfigModal from "@/components/ComboConfigModal";
import type { ProductCombo, SelectedComboData } from "@/components/ProductCombosWidget";
import { useVisaoDaLoja } from "@/components/VisaoDaLojaContext";
import { moedaDaBoutique } from "./formato";

/*
  "Compre junto": os produtos que a loja sugere levar com este.

  O desenho é o da referência: o produto da página, um "+" e as sugestões
  lado a lado, cada uma com foto, nome, preço e a caixinha "Comprar junto"
  (no celular, duas por linha, dentro do acordeão da página). O que foi
  marcado entra no carrinho junto com o produto, pelo mesmo botão da compra
  — ou pelo botão daqui, que chama aquele.

  O desenho é da Boutique. A conta do desconto, a decisão de abrir a janela de
  configuração e o formato do que sai para o carrinho são os mesmos do resto
  do sistema — um combo montado de outro jeito viraria um pedido que o admin
  não sabe ler.

  Produto sugerido simples entra com um toque. Produto com variação, medida,
  faixa de preço ou regra de quantidade abre a janela de configuração: sem
  ela, o preço mostrado aqui seria um chute.

  Quando a regra da loja esconde o preço deste visitante, o combo chega com
  `preco_oculto`: a sugestão fica, o valor não, e o item pode entrar na lista
  do mesmo jeito — a loja precifica depois.
*/

/* O que o servidor devolve do produto sugerido, na parte que decide se a
   janela de configuração precisa abrir. */
type ProdutoSugerido = {
  unit_type?: string | null;
  product_attributes?: unknown[] | null;
  product_price_tiers?: unknown[] | null;
  min_sale_qty_enabled?: boolean | null;
  max_sale_qty_enabled?: boolean | null;
  allowed_sale_qty_enabled?: boolean | null;
};

export function BoutiqueCompreJunto({
  combos,
  slug,
  corDaMarca,
  aoEscolher,
  principal,
  aoComprar,
}: {
  combos: ProductCombo[];
  /* A loja, para o servidor entregar o produto sugerido como este visitante pode vê-lo. */
  slug: string;
  corDaMarca: string;
  aoEscolher: (escolhidos: SelectedComboData[]) => void;
  /* O produto da página, o primeiro da fileira. */
  principal?: { nome: string; foto: string | null };
  /* O botão "Adicionar ao carrinho" daqui: é o adicionar do card de compra. */
  aoComprar?: () => void;
}) {
  const visao = useVisaoDaLoja();
  const [escolhidos, setEscolhidos] = useState<Record<string, SelectedComboData>>({});
  const [carregando, setCarregando] = useState<string | null>(null);
  const [janelaAberta, setJanelaAberta] = useState(false);
  const [comboEmConfiguracao, setComboEmConfiguracao] = useState<ProductCombo | null>(null);
  const [dadosDoCombo, setDadosDoCombo] = useState<Record<string, unknown> | null>(null);

  if (!combos?.length) return null;

  /* Nenhum valor para mostrar: "economize" seria promessa sem número. */
  const todosSemPreco = combos.every((combo) => combo.preco_oculto);

  const precoComDesconto = (combo: ProductCombo) => {
    const cheio = Number(combo.combo_product.price) || 0;
    if (combo.discount_type === "percentage") return cheio - (cheio * Number(combo.discount_value || 0)) / 100;
    if (combo.discount_type === "fixed") return Math.max(0, cheio - Number(combo.discount_value || 0));
    return cheio;
  };

  const publicar = (mapa: Record<string, SelectedComboData>) => {
    setEscolhidos(mapa);
    aoEscolher(Object.values(mapa));
  };

  async function alternar(combo: ProductCombo) {
    /* Sob consulta pelo cadastro, com preço visível: não há valor para somar
       ao pedido. Com o preço escondido pela regra da loja o item entra, e a
       loja põe o valor no orçamento. */
    if (combo.combo_product.price_on_request && !combo.preco_oculto) {
      toast.error("O produto sugerido está sob consulta e não pode ser adicionado direto.");
      return;
    }

    if (escolhidos[combo.id]) {
      const mapa = { ...escolhidos };
      delete mapa[combo.id];
      publicar(mapa);
      return;
    }

    setCarregando(combo.id);
    try {
      /* Pelo servidor, que entrega só o que a vitrine usa e só o que este
         visitante pode ver. Antes o navegador consultava o banco direto com a
         chave pública, e levava junto custo e preço que a regra esconde. */
      const resposta = await fetch(
        `/api/catalog/produto?slug=${encodeURIComponent(slug)}&id=${encodeURIComponent(combo.combo_product.id)}`
      );
      const corpo = (await resposta.json().catch(() => null)) as
        | { produto?: Record<string, unknown> | null; error?: string }
        | null;
      const data = (corpo?.produto || null) as (Record<string, unknown> & ProdutoSugerido) | null;
      if (!resposta.ok || !data) throw new Error(corpo?.error || "Produto não encontrado");

      const temVariacao = Array.isArray(data.product_attributes) && data.product_attributes.length > 0;
      const porMedida = data.unit_type === "square_meter" || data.unit_type === "linear_meter";
      const temFaixas = Array.isArray(data.product_price_tiers) && data.product_price_tiers.length > 0;
      const temRegraDeQuantidade =
        data.min_sale_qty_enabled || data.max_sale_qty_enabled || data.allowed_sale_qty_enabled;

      if (temVariacao || porMedida || temFaixas || temRegraDeQuantidade) {
        setDadosDoCombo(data);
        setComboEmConfiguracao(combo);
        setJanelaAberta(true);
        return;
      }

      publicar({
        ...escolhidos,
        [combo.id]: {
          combo,
          quantity: 1,
          discountedPrice: precoComDesconto(combo),
          configuration: { unit_type: data.unit_type ?? undefined },
        },
      });
    } catch {
      toast.error("Não foi possível carregar os detalhes deste produto.");
    } finally {
      setCarregando(null);
    }
  }

  function mudarQuantidade(combo: ProductCombo, nova: number) {
    const atual = escolhidos[combo.id];
    if (!atual) return;
    publicar({ ...escolhidos, [combo.id]: { ...atual, quantity: Math.max(1, nova) } });
  }

  const marcados = Object.values(escolhidos);
  const somaDosMarcados = marcados.reduce(
    (soma, escolha) => soma + (Number(escolha.discountedPrice) || 0) * (Number(escolha.quantity) || 0),
    0
  );

  return (
    <section className="bq-compre-junto">
      <div className="flex flex-col gap-6 lg:flex-row lg:items-start">
        {principal ? (
          <div className="hidden w-[300px] shrink-0 items-center gap-6 lg:flex">
            <div className="min-w-0 flex-1">
              <span className="relative block w-full overflow-hidden bg-white" style={{ aspectRatio: "1 / 1" }}>
                {principal.foto ? (
                  /* eslint-disable-next-line @next/next/no-img-element */
                  <img src={principal.foto} alt={principal.nome} className="h-full w-full object-contain" />
                ) : null}
              </span>
              <p className="mt-3 line-clamp-2 text-[14px] leading-snug text-[#333333]">{principal.nome}</p>
              <p className="mt-1 text-[12px] text-[#666666]">Este produto</p>
            </div>
            <Plus className="h-8 w-8 shrink-0 text-black" strokeWidth={1.2} aria-hidden="true" />
          </div>
        ) : null}

        <div className="grid min-w-0 flex-1 grid-cols-2 gap-x-3 gap-y-6 sm:grid-cols-3 lg:gap-x-5">
          {combos.map((combo) => {
            const escolhido = escolhidos[combo.id];
            const cheio = Number(combo.combo_product.price) || 0;
            const comDesconto = escolhido?.discountedPrice ?? precoComDesconto(combo);
            const temDesconto = combo.discount_type !== "none" && comDesconto < cheio;
            /* Escondido pela loja: nem preço nem "sob consulta", só o produto. */
            const precoEscondido = Boolean(combo.preco_oculto);
            const sobConsulta = combo.combo_product.price_on_request;

            return (
              <div key={combo.id} className="min-w-0">
                <span className="relative block w-full overflow-hidden bg-white" style={{ aspectRatio: "1 / 1" }}>
                  {combo.combo_product.image_url ? (
                    <Image
                      src={combo.combo_product.image_url}
                      alt={combo.combo_product.name}
                      fill
                      sizes="(min-width: 1024px) 260px, 50vw"
                      className="object-contain"
                      unoptimized
                    />
                  ) : null}
                </span>
                <p className="mt-3 line-clamp-2 min-h-[38px] text-[13px] leading-snug text-[#333333] sm:text-[14px]">
                  {combo.combo_product.name}
                </p>
                {precoEscondido ? null : (
                  <p className="mt-2 flex flex-wrap items-baseline gap-x-1.5 text-[12px]">
                    {sobConsulta ? (
                      <span className="text-[#666666]">{visao.textoNoLugarDoPreco}</span>
                    ) : (
                      <>
                        <span className="text-[15px] font-bold tabular-nums" style={{ color: "var(--bq-verde)" }}>
                          {moedaDaBoutique(comDesconto)}
                        </span>
                        {temDesconto ? (
                          <span className="tabular-nums text-[#808b99] line-through">{moedaDaBoutique(cheio)}</span>
                        ) : (
                          <span className="text-[#666666]">cada</span>
                        )}
                      </>
                    )}
                  </p>
                )}

                <div className="mt-2 flex flex-wrap items-center justify-between gap-2">
                  <button
                    type="button"
                    onClick={() => alternar(combo)}
                    disabled={carregando === combo.id}
                    aria-pressed={Boolean(escolhido)}
                    className="inline-flex items-center gap-2 text-[14px] text-[#333333] disabled:opacity-60"
                  >
                    <span
                      className="flex h-4 w-4 shrink-0 items-center justify-center border"
                      style={{
                        borderRadius: 2,
                        borderColor: escolhido ? "#000000" : "#b8b8b8",
                        backgroundColor: escolhido ? "#000000" : "#ffffff",
                        color: "#ffffff",
                      }}
                    >
                      {carregando === combo.id ? (
                        <Loader2 className="h-3 w-3 animate-spin text-black" />
                      ) : escolhido ? (
                        <Check className="h-3 w-3" strokeWidth={3} />
                      ) : null}
                    </span>
                    Comprar junto
                  </button>

                  {escolhido ? (
                    <div className="inline-flex items-center border" style={{ borderColor: "#e1e1e1" }}>
                      <button
                        type="button"
                        aria-label="Diminuir"
                        onClick={() => mudarQuantidade(combo, escolhido.quantity - 1)}
                        className="inline-flex h-7 w-7 items-center justify-center hover:bg-[#f3f3f3]"
                      >
                        <Minus className="h-3 w-3" />
                      </button>
                      <span className="w-7 text-center text-[12px] font-semibold tabular-nums">{escolhido.quantity}</span>
                      <button
                        type="button"
                        aria-label="Aumentar"
                        onClick={() => mudarQuantidade(combo, escolhido.quantity + 1)}
                        className="inline-flex h-7 w-7 items-center justify-center hover:bg-[#f3f3f3]"
                      >
                        <Plus className="h-3 w-3" />
                      </button>
                    </div>
                  ) : null}
                </div>
              </div>
            );
          })}
        </div>
      </div>

      {/* O resumo e o atalho: o que foi marcado entra junto com o produto. */}
      {marcados.length ? (
        <div className="mt-6 flex flex-col items-stretch gap-3 border-t pt-5 sm:flex-row sm:items-center sm:justify-between" style={{ borderColor: "#e8eaed" }}>
          <p className="text-[13px] text-[#252525]">
            {marcados.length} {marcados.length === 1 ? "item marcado" : "itens marcados"} para levar junto
            {todosSemPreco || somaDosMarcados <= 0 ? null : (
              <>
                {" · "}
                <strong className="tabular-nums">+ {moedaDaBoutique(somaDosMarcados)}</strong>
              </>
            )}
          </p>
          {aoComprar ? (
            <button type="button" onClick={aoComprar} className="bq-botao-comprar h-[46px] text-[13px] sm:w-auto sm:px-8">
              Adicionar ao carrinho com o produto
            </button>
          ) : null}
        </div>
      ) : null}

      {/* A janela de configuração é a mesma do resto do sistema: ela resolve
          variação, medida e faixa do produto sugerido, e devolve o preço já
          calculado. Ter uma cópia própria seria manter duas contas. */}
      <ComboConfigModal
        isOpen={janelaAberta}
        onClose={() => setJanelaAberta(false)}
        combo={comboEmConfiguracao}
        productData={dadosDoCombo}
        primaryColor={corDaMarca}
        onConfirm={(quantidade, configuracao) => {
          if (!comboEmConfiguracao) return;
          const preco =
            (configuracao as { resolvedUnitPrice?: number } | null)?.resolvedUnitPrice ??
            precoComDesconto(comboEmConfiguracao);
          publicar({
            ...escolhidos,
            [comboEmConfiguracao.id]: {
              combo: comboEmConfiguracao,
              quantity: quantidade,
              discountedPrice: preco,
              configuration: configuracao,
            },
          });
          setJanelaAberta(false);
        }}
      />

    </section>
  );
}
