"use client";

import { useEffect, useState } from "react";
import { Bell, BellOff, Loader2, X } from "lucide-react";

/*
  Avisos no aparelho, dentro do Chats.

  Reaproveita o mesmo registro de aparelho que a agenda ja usa: quem ligou os
  lembretes de prazo nao precisa ligar de novo aqui, e quem ligar aqui passa a
  receber os dois. A permissao e por aparelho, e nao por conta — o computador
  do balcao fica ligado o dia inteiro, o celular vai junto para a rua.

  No iPhone so funciona com o site instalado na tela inicial; em vez de pedir
  permissao e falhar calado, a faixa explica o que falta.
*/

function base64ParaBytes(base64: string) {
  const preenchido = (base64 + "=".repeat((4 - (base64.length % 4)) % 4)).replace(/-/g, "+").replace(/_/g, "/");
  const cru = atob(preenchido);
  return Uint8Array.from([...cru].map((caractere) => caractere.charCodeAt(0)));
}

type Estado = "verificando" | "indisponivel" | "precisa_instalar" | "desligado" | "ligado" | "negado";

const GUARDA_DISPENSADO = "ktl:chats-avisos-dispensado";

export default function AtivarAvisos() {
  const [estado, setEstado] = useState<Estado>("verificando");
  const [ocupado, setOcupado] = useState(false);
  const [dispensado, setDispensado] = useState(true);
  const [erro, setErro] = useState<string | null>(null);

  const chavePublica = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY;

  useEffect(() => {
    setDispensado(window.localStorage.getItem(GUARDA_DISPENSADO) === "1");

    void (async () => {
      if (!chavePublica) return setEstado("indisponivel");
      if (!("serviceWorker" in navigator) || !("PushManager" in window)) {
        const ehApple = /iPad|iPhone|iPod/.test(navigator.userAgent);
        return setEstado(ehApple ? "precisa_instalar" : "indisponivel");
      }
      if (Notification.permission === "denied") return setEstado("negado");

      try {
        const registro = await navigator.serviceWorker.register("/sw.js");
        const atual = await registro.pushManager.getSubscription();
        setEstado(atual ? "ligado" : "desligado");
      } catch {
        setEstado("indisponivel");
      }
    })();
  }, [chavePublica]);

  async function ligar() {
    setOcupado(true);
    setErro(null);
    try {
      const permissao = await Notification.requestPermission();
      if (permissao !== "granted") {
        setEstado(permissao === "denied" ? "negado" : "desligado");
        return;
      }
      const registro = await navigator.serviceWorker.ready;
      const assinatura = await registro.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: base64ParaBytes(chavePublica!),
      });
      const resposta = await fetch("/api/agenda/push/subscrever", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ assinatura: assinatura.toJSON(), user_agent: navigator.userAgent }),
      });
      if (!resposta.ok) {
        throw new Error((await resposta.json().catch(() => null))?.error || "Não consegui ativar.");
      }
      setEstado("ligado");
    } catch (falha) {
      setErro(falha instanceof Error ? falha.message : "Não consegui ativar os avisos.");
    } finally {
      setOcupado(false);
    }
  }

  function dispensar() {
    window.localStorage.setItem(GUARDA_DISPENSADO, "1");
    setDispensado(true);
  }

  /* Quem ja ligou nao precisa ver faixa nenhuma. */
  if (estado === "verificando" || estado === "indisponivel" || estado === "ligado") return null;
  if (dispensado) return null;

  if (estado === "precisa_instalar") {
    return (
      <div className="chat-convite">
        <Bell size={15} />
        <span>
          Para receber no iPhone, toque em Compartilhar e escolha <strong>Adicionar à Tela de Início</strong>.
        </span>
        <button type="button" onClick={dispensar} aria-label="Dispensar">
          <X size={14} />
        </button>
      </div>
    );
  }

  if (estado === "negado") {
    return (
      <div className="chat-convite">
        <BellOff size={15} />
        <span>Os avisos estão bloqueados neste aparelho. Libere nas configurações do navegador.</span>
        <button type="button" onClick={dispensar} aria-label="Dispensar">
          <X size={14} />
        </button>
      </div>
    );
  }

  return (
    <div className="chat-convite">
      <Bell size={15} />
      <span>Receba aviso de mensagem nova mesmo com o Chats fechado.</span>
      <button type="button" className="chat-convite-ligar" onClick={() => void ligar()} disabled={ocupado}>
        {ocupado ? <Loader2 size={13} className="chat-girando" /> : null}
        Ativar
      </button>
      <button type="button" onClick={dispensar} aria-label="Agora não">
        <X size={14} />
      </button>
      {erro ? <span className="chat-convite-erro">{erro}</span> : null}
    </div>
  );
}
