"use client";

import { useCallback, useEffect, useRef, useState, type ReactNode } from "react";
import { createPortal } from "react-dom";
import { estiloSituacao, horarioDoEvento, type EventoAgenda } from "./tipos";

/**
 * Tooltip proprio da agenda.
 *
 * O `title` do navegador aparece depois de um segundo e meio, sem cor, sem
 * hierarquia, e some sozinho — inutil para ler o compromisso de relance. Aqui
 * a dica mostra titulo, horario, categoria e situacao com a mesma linguagem
 * dos cartoes.
 *
 * A peca entrega handlers, e nao um componente-casca: envolver cada cartao
 * num wrapper quebraria o posicionamento absoluto da grade por hora, onde o
 * bloco e posicionado por `top`/`left` dentro da coluna do dia.
 *
 * Um tooltip so por tela, comandado por quem esta sob o ponteiro — montar um
 * por cartao encheria a arvore de nos ociosos numa semana cheia.
 */

const ATRASO_MS = 320;
const MARGEM = 10;

type Estado = { alvo: DOMRect; conteudo: ReactNode } | null;

export function useDica() {
  const [estado, setEstado] = useState<Estado>(null);
  const timer = useRef<number | null>(null);

  const limpar = useCallback(() => {
    if (timer.current) window.clearTimeout(timer.current);
    timer.current = null;
  }, []);

  const fechar = useCallback(() => {
    limpar();
    setEstado(null);
  }, [limpar]);

  useEffect(() => limpar, [limpar]);

  /* Fecha ao rolar: a dica e posicionada em coordenadas de tela, entao ficaria
     apontando para o lugar errado assim que a grade se move. */
  useEffect(() => {
    if (!estado) return;
    window.addEventListener("scroll", fechar, { capture: true, passive: true });
    return () => window.removeEventListener("scroll", fechar, { capture: true });
  }, [estado, fechar]);

  const dicaProps = useCallback(
    (conteudo: ReactNode) => ({
      onPointerEnter: (e: React.PointerEvent) => {
        if (e.pointerType !== "mouse") return;
        const alvo = e.currentTarget as HTMLElement;
        limpar();
        timer.current = window.setTimeout(() => {
          setEstado({ alvo: alvo.getBoundingClientRect(), conteudo });
        }, ATRASO_MS);
      },
      onPointerLeave: fechar,
      /* Sai do caminho no clique e no arrasto: manter a dica aberta enquanto a
         pessoa move o compromisso atrapalharia a mira. */
      onPointerDown: fechar,
    }),
    [fechar, limpar]
  );

  const camada = estado ? <Balao alvo={estado.alvo} conteudo={estado.conteudo} /> : null;

  return { dicaProps, camada, fecharDica: fechar };
}

function Balao({ alvo, conteudo }: { alvo: DOMRect; conteudo: ReactNode }) {
  const ref = useRef<HTMLDivElement>(null);
  const [pos, setPos] = useState<{ left: number; top: number } | null>(null);

  /* Mede depois de montar: sem o tamanho real do balao nao da para saber se
     ele cabe acima do cartao nem como centralizar sem vazar da tela. */
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const { width, height } = el.getBoundingClientRect();

    let left = alvo.left + alvo.width / 2 - width / 2;
    left = Math.max(MARGEM, Math.min(left, window.innerWidth - width - MARGEM));

    const acima = alvo.top - height - 8;
    const top = acima >= MARGEM ? acima : Math.min(alvo.bottom + 8, window.innerHeight - height - MARGEM);

    setPos({ left, top });
  }, [alvo]);

  return createPortal(
    <div
      ref={ref}
      role="tooltip"
      className="pointer-events-none fixed z-[80] w-max max-w-[290px] rounded-[10px] border border-[var(--ag-border)] bg-[var(--ag-surface)] px-3 py-2.5 shadow-[var(--ag-sombra-alta)]"
      style={{
        left: pos?.left ?? 0,
        top: pos?.top ?? 0,
        opacity: pos ? 1 : 0,
        transition: "opacity 120ms ease-out",
      }}
    >
      {conteudo}
    </div>,
    document.body
  );
}

/** Conteudo padrao da dica de um evento — o mesmo em todas as visoes. */
export function DicaEvento({ evento }: { evento: EventoAgenda }) {
  const { inicioMin, fimMin } = horarioDoEvento(evento);
  const situacao = estiloSituacao(evento.situacao);

  const hora =
    inicioMin === null
      ? "Sem horário marcado"
      : fimMin !== null
        ? `${fmt(inicioMin)} às ${fmt(fimMin)}`
        : fmt(inicioMin);

  /* O subtitulo carrega "HH:MM · Cliente" numa string so; o horario ja tem
     linha propria aqui, entao fica apenas o que sobra. */
  const complemento = String(evento.subtitulo || "")
    .replace(/^\d{2}:\d{2}(–\d{2}:\d{2})?\s*(·\s*)?/, "")
    .trim();

  return (
    <>
      <p className="text-[12.5px] font-semibold leading-[1.35] text-[var(--ag-text)]">{evento.titulo}</p>

      <p className="mt-[5px] flex items-center gap-1.5 text-[11.5px] font-medium tabular-nums text-[var(--ag-text-3)]">
        {hora}
      </p>

      {complemento && (
        <p className="mt-[3px] truncate text-[11.5px] text-[var(--ag-text-3)]">{complemento}</p>
      )}

      <div className="mt-2 flex flex-wrap items-center gap-1.5">
        <span
          className="flex items-center gap-1.5 rounded-full px-[8px] py-[3px] text-[10.5px] font-medium"
          style={{ background: `${evento.categoria_cor}17`, color: evento.categoria_cor }}
        >
          <span
            aria-hidden
            className="h-[6px] w-[6px] rounded-full"
            style={{ background: evento.categoria_cor }}
          />
          {evento.categoria_nome}
        </span>
        {situacao.texto && (
          <span
            className="rounded-full px-[8px] py-[3px] text-[10.5px] font-medium"
            style={{ background: situacao.fundo, color: situacao.cor }}
          >
            {situacao.texto}
          </span>
        )}
      </div>
    </>
  );
}

function fmt(min: number) {
  return `${String(Math.floor(min / 60)).padStart(2, "0")}:${String(min % 60).padStart(2, "0")}`;
}
