"use client";

import { useCallback, useMemo, useRef, useState, type ReactNode } from "react";
import Link from "next/link";
import { ChevronLeft, ChevronRight, Home } from "lucide-react";
import { VendorCardDoProduto, fotoDoProduto, precoInicial, type VendorProduto } from "./VendorCardDoProduto";
import {
  PRODUTOS_POR_SECAO,
  VendorBannerDuplo,
  VendorCirculos,
  VendorHero,
  VendorSecaoDeProdutos,
  type VendorBanner,
} from "./VendorBlocosDaHome";
import { VendorSecoesDaHome, type VendorSecaoDaHome } from "./VendorSecoesDaHome";
import { VendorTarja, type VendorItemDaTarja } from "./VendorTarja";
import StoriesCarousel from "@/components/stories/StoriesCarousel";
import { VendorProvaSocial, type VendorProvaSocialAjustes } from "./VendorProvaSocial";
import { useVisaoDaLoja } from "@/components/VisaoDaLojaContext";
import { moedaDoVendor } from "./formato";

type OrdemDaLista = "nome" | "menor" | "maior";
import type { VendorCategoria } from "./VendorShell";

/*
  A home do Vendor.

  A ordem dos blocos não é decoração: grade de produtos → prova social ou
  banner → grade de produtos. Nunca dois blocos que não são produto seguidos,
  senão a página vira folheto e o cliente perde o fio da compra.

  Toda faixa usa o mesmo container (`max-w-6xl px-4`). É o que mantém tudo
  alinhado na mesma coluna vertical, do topo ao rodapé.
*/

export type { VendorBanner };

export type VendorSecao = {
  titulo: string;
  categoriaId?: string | null;
  categoriaSlug?: string | null;
  produtos: VendorProduto[];
};

/* Quantos cards a grade da categoria mostra por vez: 216 de uma vez travavam
   o celular. "Ver mais" solta o próximo lote, sem nova ida ao servidor. */
const LOTE_DA_GRADE = 40;

export type VendorAvaliacao = {
  id: string;
  autor: string;
  data?: string | null;
  nota: number;
  texto?: string | null;
};

function Estrelas({ nota, tamanho = 12 }: { nota: number; tamanho?: number }) {
  return (
    <span className="inline-flex items-center gap-0.5" aria-label={`${nota} de 5`}>
      {[1, 2, 3, 4, 5].map((n) => (
        <svg
          key={n}
          width={tamanho}
          height={tamanho}
          viewBox="0 0 24 24"
          fill={n <= Math.round(nota) ? "#f59e0b" : "#d4d4d8"}
          aria-hidden="true"
        >
          <path d="M12 2l2.9 6.2 6.6.9-4.8 4.6 1.2 6.6L12 17.2 6.1 20.3l1.2-6.6L2.5 9.1l6.6-.9z" />
        </svg>
      ))}
    </span>
  );
}

/* A prova social. Um trilho horizontal com setas meio para fora do container
   — é o que avisa que existe mais coisa à direita sem precisar de legenda. */
function VendorAvaliacoes({
  avaliacoes,
  media,
  nomeDaLoja,
  logoUrl,
  slug,
}: {
  avaliacoes: VendorAvaliacao[];
  media: number;
  nomeDaLoja: string;
  logoUrl?: string | null;
  slug: string;
}) {
  const trilho = useRef<HTMLDivElement | null>(null);

  const rolar = useCallback((direcao: -1 | 1) => {
    const caixa = trilho.current;
    if (!caixa) return;
    caixa.scrollBy({ left: direcao * 300, behavior: "smooth" });
  }, []);

  if (!avaliacoes.length) return null;

  return (
    <section className="w-full pb-8 sm:pb-10">
      <div className="mx-auto max-w-6xl px-4">
        <div className="space-y-4 border-t pt-6 sm:space-y-6 sm:pt-8" style={{ borderColor: "var(--vd-border)" }}>
          <div className="flex flex-wrap items-start justify-between gap-4">
            <div className="flex items-center gap-3">
              {logoUrl ? (
                /* eslint-disable-next-line @next/next/no-img-element */
                <img
                  src={logoUrl}
                  alt=""
                  className="h-10 w-10 border bg-white object-contain p-1 sm:h-12 sm:w-12"
                  style={{ borderRadius: "var(--vd-radius-xl)", borderColor: "var(--vd-border)" }}
                />
              ) : null}
              <div>
                <p className="text-sm font-semibold">{nomeDaLoja}</p>
                <p className="flex items-center gap-1.5 text-xs text-[var(--vd-muted-fg)]">
                  <Estrelas nota={media} />
                  {media.toFixed(1).replace(".", ",")} · {avaliacoes.length}{" "}
                  {avaliacoes.length === 1 ? "avaliação" : "avaliações"}
                </p>
              </div>
            </div>
          </div>

          <div className="relative">
            <div ref={trilho} className="vd-sem-barra flex snap-x gap-3 overflow-x-auto scroll-smooth">
              {avaliacoes.map((avaliacao) => (
                <article
                  key={avaliacao.id}
                  className="w-56 shrink-0 snap-start space-y-2 border bg-[var(--vd-surface)] p-3 sm:w-72 sm:space-y-2.5 sm:p-4"
                  style={{ borderRadius: "var(--vd-radius-xl)", borderColor: "var(--vd-border)" }}
                >
                  <div className="flex items-center gap-2">
                    <span
                      className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-xs font-bold"
                      style={{ backgroundColor: "var(--vd-muted-bg)", color: "var(--vd-muted-fg)" }}
                    >
                      {avaliacao.autor.slice(0, 1).toUpperCase()}
                    </span>
                    <div className="min-w-0">
                      <p className="truncate text-[13px] font-semibold">{avaliacao.autor}</p>
                      {avaliacao.data ? (
                        <p className="text-[11px] text-[var(--vd-muted-fg)]">{avaliacao.data}</p>
                      ) : null}
                    </div>
                  </div>
                  <Estrelas nota={avaliacao.nota} />
                  {avaliacao.texto ? (
                    <p className="line-clamp-4 text-[12.5px] leading-relaxed text-[var(--vd-muted-fg)]">
                      {avaliacao.texto}
                    </p>
                  ) : null}
                </article>
              ))}
            </div>

            {avaliacoes.length > 2 ? (
              <>
                <button
                  type="button"
                  aria-label="Anteriores"
                  onClick={() => rolar(-1)}
                  className="absolute -left-3 top-1/2 z-10 hidden h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full border bg-[var(--vd-surface)] shadow transition-colors sm:flex"
                  style={{ borderColor: "var(--vd-border)" }}
                >
                  <ChevronLeft className="h-4 w-4" />
                </button>
                <button
                  type="button"
                  aria-label="Próximas"
                  onClick={() => rolar(1)}
                  className="absolute -right-3 top-1/2 z-10 hidden h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full border bg-[var(--vd-surface)] shadow transition-colors sm:flex"
                  style={{ borderColor: "var(--vd-border)" }}
                >
                  <ChevronRight className="h-4 w-4" />
                </button>
              </>
            ) : null}
          </div>

          <div className="flex justify-center">
            <Link
              href={`/${slug}`}
              className="flex items-center gap-1.5 text-sm text-[var(--vd-muted-fg)] transition-colors hover:text-[var(--vd-foreground)]"
            >
              Ver a loja inteira
            </Link>
          </div>
        </div>
      </div>
    </section>
  );
}

export function VendorHome({
  slug,
  produtos,
  categorias,
  banners,
  avaliacoes,
  mediaDasAvaliacoes,
  nomeDaLoja,
  logoUrl,
  tituloDaPagina,
  subtitulo,
  fotoDaPagina,
  tarja,
  corDaMarca,
  clienteId,
  favoritos,
  stories,
  provaSocial,
  secoesDaHome,
  envolverSecao,
}: {
  slug: string;
  produtos: VendorProduto[];
  categorias: VendorCategoria[];
  banners: VendorBanner[];
  avaliacoes: VendorAvaliacao[];
  mediaDasAvaliacoes: number;
  nomeDaLoja: string;
  logoUrl?: string | null;
  /* Quando a página é de categoria ou de busca, o Vendor mostra uma grade
     só, com este título. Sem título, é a home inteira. */
  tituloDaPagina?: string | null;
  subtitulo?: string | null;
  /* A foto que representa a página de categoria, no cartão do topo. */
  fotoDaPagina?: string | null;
  /* A tarja de vantagens, que fica logo abaixo do banner. */
  tarja?: VendorItemDaTarja[] | null;
  corDaMarca?: string;
  /* Quem está logado no portal, para o coração de favorito. */
  clienteId?: string | null;
  favoritos?: string[] | null;
  /* Os stories da loja. O player é o mesmo do resto do sistema: é conteúdo
     que a loja publica, não desenho de template. */
  stories?: Array<Record<string, unknown>> | null;
  /* "Fulana comprou há 3 minutos" — as mesmas chaves do catálogo. */
  provaSocial?: VendorProvaSocialAjustes | null;
  /* A página inicial montada pelo editor do painel. null/ausente = a home
     automática de sempre (mais vendidos + categorias). */
  secoesDaHome?: VendorSecaoDaHome[] | null;
  /* Só o editor passa: a moldura de cada seção. */
  envolverSecao?: (secao: VendorSecaoDaHome, indice: number, conteudo: ReactNode) => ReactNode;
}) {
  /* A foto de cada categoria vem do primeiro produto dela: é a imagem que o
     cliente já associa àquele grupo. */
  const fotosDasCategorias = useMemo(() => {
    const mapa = new Map<string, string>();
    for (const produto of produtos) {
      const categoria = (produto as VendorProduto & { category_id?: string }).category_id;
      if (!categoria || mapa.has(categoria)) continue;
      const foto = fotoDoProduto(produto);
      if (foto) mapa.set(categoria, foto);
    }
    return mapa;
  }, [produtos]);

  const raizes = useMemo(() => categorias.filter((c) => !c.parent_id), [categorias]);

  /* As regras da loja para este visitante. Sem preço na tela, não há filtro
     nem ordenação por preço: os dois entregariam, pela posição na lista, o
     número que a loja escondeu. */
  const visao = useVisaoDaLoja();
  const comPreco = visao.mostrarPreco;

  /* A ordenação da listagem. Fica no cliente porque é troca de vitrine, não
     de dados: ninguém precisa de uma volta ao servidor para ver o mais
     barato primeiro. */
  const [ordem, setOrdem] = useState<OrdemDaLista>("nome");
  const ordemEfetiva: OrdemDaLista = comPreco ? ordem : "nome";
  /* O filtro de preço da listagem. Os limites saem dos próprios produtos:
     uma faixa fixa de 0 a 1000 não serve nem para quem vende adesivo nem para
     quem vende letreiro. */
  const limitesDePreco = useMemo(() => {
    if (!comPreco) return null;
    const precos = produtos
      .filter((produto) => !produto.price_on_request)
      .map((produto) => precoInicial(produto))
      .filter((preco) => Number.isFinite(preco) && preco > 0);
    if (!precos.length) return null;
    const menor = Math.floor(Math.min(...precos));
    const maior = Math.ceil(Math.max(...precos));
    return maior > menor ? { menor, maior } : null;
  }, [produtos, comPreco]);

  /* O teto guarda a qual listagem pertence. Trocou de categoria, ele volta ao
     começo sozinho: o teto da anterior podia esconder a lista inteira da nova. */
  const chaveDaLista = `${tituloDaPagina || ""}:${produtos.length}`;
  const [lote, setLote] = useState<{ lista: string; quantos: number }>({ lista: "", quantos: LOTE_DA_GRADE });
  const quantosMostrar = lote.lista === chaveDaLista ? lote.quantos : LOTE_DA_GRADE;
  const [filtroDePreco, setFiltroDePreco] = useState<{ lista: string; teto: number | null }>({
    lista: chaveDaLista,
    teto: null,
  });
  const tetoDoPreco = filtroDePreco.lista === chaveDaLista ? filtroDePreco.teto : null;
  const setTetoDoPreco = (valor: number | null) => setFiltroDePreco({ lista: chaveDaLista, teto: valor });

  const tetoAtual = tetoDoPreco ?? limitesDePreco?.maior ?? 0;

  const produtosOrdenados = useMemo(() => {
    const filtrada = limitesDePreco && tetoDoPreco !== null
      ? produtos.filter((produto) => produto.price_on_request || precoInicial(produto) <= tetoDoPreco + 0.001)
      : produtos;
    const lista = [...filtrada];
    /* Produto sob consulta (ou com o preço escondido pela loja) não tem
       número para comparar: entrava como R$ 0 e abria a lista do "menor
       preço". Vai para o fim, nas duas direções. */
    const semNumero = (produto: VendorProduto) => Boolean(produto.price_on_request);
    const porPreco = (direcao: 1 | -1) => (a: VendorProduto, b: VendorProduto) => {
      const aSem = semNumero(a);
      const bSem = semNumero(b);
      if (aSem !== bSem) return aSem ? 1 : -1;
      if (aSem) return a.name.localeCompare(b.name, "pt-BR");
      return (precoInicial(a) - precoInicial(b)) * direcao;
    };
    if (ordemEfetiva === "menor") return lista.sort(porPreco(1));
    if (ordemEfetiva === "maior") return lista.sort(porPreco(-1));
    return lista.sort((a, b) => a.name.localeCompare(b.name, "pt-BR"));
  }, [produtos, ordemEfetiva, limitesDePreco, tetoDoPreco]);

  /* As seções da home: os mais recentes e depois três categorias com
     produto. Sem categoria cadastrada, vira uma grade só. */
  const secoes = useMemo<VendorSecao[]>(() => {
    if (tituloDaPagina) return [];
    const lista: VendorSecao[] = [];
    if (produtos.length) {
      lista.push({ titulo: "Mais vendidos", produtos: produtos.slice(0, PRODUTOS_POR_SECAO) });
    }
    for (const categoria of raizes) {
      const doGrupo = produtos.filter(
        (p) => (p as VendorProduto & { category_id?: string }).category_id === categoria.id
      );
      if (doGrupo.length < 2) continue;
      lista.push({
        titulo: categoria.name,
        categoriaId: categoria.id,
        categoriaSlug: categoria.slug || categoria.id,
        produtos: doGrupo.slice(0, PRODUTOS_POR_SECAO),
      });
      if (lista.length >= 4) break;
    }
    return lista;
  }, [produtos, raizes, tituloDaPagina]);

  /* Página de categoria ou de busca: uma grade só, sem hero nem prova
     social. Quem chegou aqui já sabe o que procura. */
  if (tituloDaPagina) {
    return (
      <div className="pb-10">
        <section className="mx-auto w-full max-w-6xl px-4 py-6">
          {/* A trilha e o cartão de identidade da página: quem chegou por um
              link precisa saber onde caiu antes de olhar os preços. */}
          <nav className="mb-4 flex items-center gap-1.5 text-xs text-[var(--vd-muted-fg)]">
            <Link href={`/${slug}`} className="flex items-center gap-1 transition-colors hover:text-[var(--vd-foreground)]">
              <Home className="h-3.5 w-3.5" />
              Início
            </Link>
            <ChevronRight className="h-3 w-3" />
            <span className="truncate font-medium text-[var(--vd-foreground)]">{tituloDaPagina}</span>
          </nav>

          <div
            className="mb-6 flex items-center gap-4 border p-4"
            style={{
              borderRadius: "var(--vd-radius-xl)",
              borderColor: "var(--vd-border)",
              backgroundColor: "color-mix(in srgb, var(--vd-muted-bg) 30%, var(--vd-surface))",
            }}
          >
            {fotoDaPagina ? (
              <span
                className="h-14 w-14 shrink-0 overflow-hidden bg-white sm:h-16 sm:w-16"
                style={{ borderRadius: "var(--vd-radius-lg)" }}
              >
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img src={fotoDaPagina} alt="" className="h-full w-full object-cover" />
              </span>
            ) : null}
            <h1 className="text-xl font-bold tracking-tight sm:text-2xl">{tituloDaPagina}</h1>
          </div>

          <div className="mb-6 flex flex-wrap items-center justify-between gap-3">
            <p className="text-[13px] text-[var(--vd-muted-fg)]">
              {subtitulo && tetoDoPreco === null
                ? subtitulo
                : `${produtosOrdenados.length} ${produtosOrdenados.length === 1 ? "produto" : "produtos"}`}
            </p>

            {limitesDePreco ? (
              <label
                className="flex min-w-[220px] flex-1 items-center gap-2 text-[13px] text-[var(--vd-muted-fg)] sm:max-w-[320px] sm:flex-none"
                title="Arraste para mostrar só os produtos até este preço"
              >
                <span className="shrink-0">Preço até</span>
                <input
                  type="range"
                  min={limitesDePreco.menor}
                  max={limitesDePreco.maior}
                  step={1}
                  value={tetoAtual}
                  onChange={(e) => setTetoDoPreco(Number(e.target.value))}
                  aria-label="Preço máximo"
                  className="vd-faixa h-1.5 flex-1 cursor-pointer appearance-none rounded-full"
                  style={{
                    accentColor: corDaMarca || "var(--vd-primary)",
                    /* A parte cheia da trilha vai até o valor escolhido. */
                    ["--vd-faixa-cheia" as string]: `${
                      limitesDePreco.maior > limitesDePreco.menor
                        ? Math.round(((tetoAtual - limitesDePreco.menor) / (limitesDePreco.maior - limitesDePreco.menor)) * 100)
                        : 100
                    }%`,
                  }}
                />
                <span className="w-[86px] shrink-0 text-right font-semibold tabular-nums text-[var(--vd-foreground)]">
                  {moedaDoVendor(tetoAtual)}
                </span>
                {tetoDoPreco !== null ? (
                  <button
                    type="button"
                    onClick={() => setTetoDoPreco(null)}
                    className="shrink-0 text-[12px] underline underline-offset-2"
                  >
                    limpar
                  </button>
                ) : null}
              </label>
            ) : null}
            {/* Sem preço na tela só sobraria "Nome (A-Z)", que já é a ordem
                de sempre: o seletor some. */}
            {produtos.length > 1 && comPreco ? (
              <label className="flex items-center gap-2 text-[13px] text-[var(--vd-muted-fg)]">
                Ordenar por
                <select
                  value={ordemEfetiva}
                  onChange={(e) => setOrdem(e.target.value as OrdemDaLista)}
                  className="h-9 border bg-[var(--vd-surface)] px-2 text-[13px] outline-none"
                  style={{ borderRadius: "var(--vd-radius-lg)", borderColor: "var(--vd-border)" }}
                >
                  <option value="nome">Nome (A-Z)</option>
                  <option value="menor">Menor preço</option>
                  <option value="maior">Maior preço</option>
                </select>
              </label>
            ) : null}
          </div>

          {produtosOrdenados.length ? (
            <>
            <div className="grid grid-cols-2 gap-x-3 gap-y-8 sm:gap-x-4 lg:grid-cols-4">
              {produtosOrdenados.slice(0, quantosMostrar).map((produto) => (
                <VendorCardDoProduto
                  key={produto.id}
                  produto={produto}
                  slug={slug}
                  clienteId={clienteId}
                  favoritos={favoritos}
                  corDaMarca={corDaMarca}
                />
              ))}
            </div>
            {produtosOrdenados.length > quantosMostrar ? (
              <div className="mt-8 flex justify-center">
                <button
                  type="button"
                  onClick={() => setLote({ lista: chaveDaLista, quantos: quantosMostrar + LOTE_DA_GRADE })}
                  className="border px-6 py-2.5 text-[13px] font-semibold transition-colors hover:bg-[var(--vd-muted-bg)]"
                  style={{ borderRadius: "var(--vd-radius-lg)", borderColor: "var(--vd-border)" }}
                >
                  Ver mais produtos ({produtosOrdenados.length - quantosMostrar} restantes)
                </button>
              </div>
            ) : null}
            </>
          ) : (
            <div
              className="border border-dashed px-6 py-16 text-center"
              style={{ borderRadius: "var(--vd-radius-xl)", borderColor: "var(--vd-border)" }}
            >
              <p className="text-sm font-semibold">Nada encontrado por aqui</p>
              <p className="mt-1 text-[13px] text-[var(--vd-muted-fg)]">
                Tente outra categoria ou fale com a loja pelo WhatsApp.
              </p>
            </div>
          )}
        </section>
      </div>
    );
  }

  const bannersDoMeio = banners.slice(1, 3);

  /* A home que a loja montou no editor: o topo (banner, tarja, stories) é o
     mesmo; depois dele vêm as seções na ordem escolhida. */
  if (secoesDaHome) {
    return (
      <div className="pb-6">
        <VendorHero banners={banners} slug={slug} />
        <VendorTarja itens={tarja || []} corDaMarca={corDaMarca || "#111827"} />
        {stories?.length ? (
          <div className="mx-auto w-full max-w-6xl px-4 pt-4">
            <StoriesCarousel groups={stories as never} primaryColor={corDaMarca || "#111827"} slug={slug} />
          </div>
        ) : null}
        <VendorSecoesDaHome
          secoes={secoesDaHome}
          envolver={envolverSecao}
          contarCliques
          slug={slug}
          produtos={produtos}
          categorias={categorias}
          clienteId={clienteId}
          favoritos={favoritos}
          corDaMarca={corDaMarca}
        />
        {provaSocial?.ligado ? (
          <VendorProvaSocial
            slug={slug}
            produtos={produtos as never}
            ligado={provaSocial.ligado}
            intervaloSegundos={provaSocial.intervaloSegundos}
            duracaoSegundos={provaSocial.duracaoSegundos}
            quantosCabem={provaSocial.quantosCabem}
            posicao={provaSocial.posicao}
          />
        ) : null}
      </div>
    );
  }

  return (
    <div className="pb-6">
      <VendorHero banners={banners} slug={slug} />
      {/* A tarja vem DEPOIS do banner: antes dele, empurrava a oferta para
          baixo e roubava a primeira olhada. */}
      <VendorTarja itens={tarja || []} corDaMarca={corDaMarca || "#111827"} />

      {/* Os stories entram antes dos círculos de categoria: são o que a loja
          publicou hoje, e envelhecem — a categoria fica lá sempre. */}
      {stories?.length ? (
        <div className="mx-auto w-full max-w-6xl px-4 pt-4">
          <StoriesCarousel groups={stories as never} primaryColor={corDaMarca || "#111827"} slug={slug} />
        </div>
      ) : null}
      <VendorCirculos categorias={raizes} slug={slug} fotos={fotosDasCategorias} />

      {secoes.map((secao, indice) => (
        <div key={`${secao.titulo}-${indice}`}>
          <VendorSecaoDeProdutos
            titulo={secao.titulo}
            produtos={secao.produtos}
            slug={slug}
            clienteId={clienteId}
            favoritos={favoritos}
            corDaMarca={corDaMarca}
            verTudoHref={secao.categoriaSlug ? `/${slug}/c/${secao.categoriaSlug}` : null}
          />

          {/* Entre uma grade e outra entra prova social ou banner, nunca dois
              blocos do mesmo tipo seguidos. */}
          {indice === 0 ? (
            <VendorAvaliacoes
              avaliacoes={avaliacoes}
              media={mediaDasAvaliacoes}
              nomeDaLoja={nomeDaLoja}
              logoUrl={logoUrl}
              slug={slug}
            />
          ) : null}
          {indice === 1 && bannersDoMeio.length >= 2 ? (
            <VendorBannerDuplo banners={bannersDoMeio} slug={slug} />
          ) : null}
        </div>
      ))}

      {!secoes.length && produtos.length ? (
        <VendorSecaoDeProdutos
          titulo="Nossos produtos"
          produtos={produtos.slice(0, 8)}
          slug={slug}
          clienteId={clienteId}
          favoritos={favoritos}
          corDaMarca={corDaMarca}
        />
      ) : null}

      {provaSocial?.ligado ? (
        <VendorProvaSocial
          slug={slug}
          produtos={produtos as never}
          ligado={provaSocial.ligado}
          intervaloSegundos={provaSocial.intervaloSegundos}
          duracaoSegundos={provaSocial.duracaoSegundos}
          quantosCabem={provaSocial.quantosCabem}
          posicao={provaSocial.posicao}
        />
      ) : null}
    </div>
  );
}
