import { useEffect, useState } from "react";
import { useServerFn } from "@tanstack/react-start";
import { Bell, BellOff, Download, ExternalLink, Loader2 } from "lucide-react";
import { siteLink } from "@/lib/site";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { getPushPublicKey, savePushSubscription } from "@/lib/push.functions";
import {
  ensureServiceWorkerRegistration,
  getServiceWorkerBlockReason,
  pushSupported,
  type ServiceWorkerBlockReason,
} from "@/lib/pwa";



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

function toKeys(sub: PushSubscription) {
  const json = sub.toJSON() as { keys?: { p256dh?: string; auth?: string } };
  return { p256dh: json.keys?.p256dh ?? "", auth: json.keys?.auth ?? "" };
}

/** Push notifications are permanently on; this row only shows/repairs state. */
export function PushNotificationsRow() {
  const publicKeyFn = useServerFn(getPushPublicKey);
  const saveFn = useServerFn(savePushSubscription);

  const [supported, setSupported] = useState(false);
  const [enabled, setEnabled] = useState(false);
  const [blocked, setBlocked] = useState(false);
  const [busy, setBusy] = useState(false);
  const [contextBlock, setContextBlock] = useState<ServiceWorkerBlockReason | null>(null);

  useEffect(() => {
    if (!pushSupported()) return;
    setSupported(true);
    setContextBlock(getServiceWorkerBlockReason());
    setBlocked(Notification.permission === "denied");

    const refresh = async () => {
      const reg = await navigator.serviceWorker.getRegistration("/").catch(() => null);
      const sub = await reg?.pushManager.getSubscription().catch(() => null);
      setEnabled(Boolean(sub) && Notification.permission === "granted");
      setBlocked(Notification.permission === "denied");
    };
    void refresh();
    window.addEventListener("focus", refresh);
    document.addEventListener("visibilitychange", refresh);
    return () => {
      window.removeEventListener("focus", refresh);
      document.removeEventListener("visibilitychange", refresh);
    };
  }, []);

  function openStandaloneApp() {
    const currentHost = window.location.hostname;
    const isPreview = currentHost.startsWith("id-preview--") || currentHost.startsWith("preview--");
    const destination = isPreview || !import.meta.env.PROD ? siteLink("/app/profile") : window.location.href;
    window.open(destination, "_blank", "noopener,noreferrer");
  }

  async function enable() {
    setBusy(true);
    try {
      const permission =
        Notification.permission === "granted" ? "granted" : await Notification.requestPermission();
      if (permission !== "granted") {
        setBlocked(permission === "denied");
        toast.error(
          permission === "denied"
            ? "Notifications are blocked. Allow them for Billsline in your browser settings."
            : "Notification permission was dismissed.",
        );
        return;
      }

      const reg = await ensureServiceWorkerRegistration();
      if (!reg) {
        setContextBlock(getServiceWorkerBlockReason());
        toast.info("Continue in the standalone Billsline app to activate alerts.");
        return;
      }

      const { publicKey } = await publicKeyFn();
      if (!publicKey) {
        toast.error("Push is not configured yet. Please try again later.");
        return;
      }

      const existing = await reg.pushManager.getSubscription();
      const sub =
        existing ??
        (await reg.pushManager.subscribe({
          userVisibleOnly: true,
          applicationServerKey: urlBase64ToUint8Array(publicKey) as unknown as BufferSource,
        }));

      const keys = toKeys(sub);
      await saveFn({ data: { endpoint: sub.endpoint, ...keys, userAgent: navigator.userAgent.slice(0, 400) } });
      setEnabled(true);
      setBlocked(false);
      toast.success("Push notifications active on this device");
    } catch (e) {
      toast.error((e as Error)?.message || "Could not activate notifications");
    } finally {
      setBusy(false);
    }
  }

  const canRepair =
    supported && !enabled && !blocked && (!contextBlock || contextBlock === "disabled");

  // Silent self-repair: if the browser allows it, keep the subscription alive
  // without ever asking the user to toggle anything.
  useEffect(() => {
    if (canRepair && !busy && Notification.permission === "granted") void enable();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [canRepair]);

  if (!supported) return null;

  return (
    <div className="flex items-center justify-between gap-3 px-4 py-3">
      <div className="flex items-center gap-3">
        <span className="grid h-9 w-9 place-items-center rounded-full bg-primary/10 text-primary">
          {blocked ? <BellOff className="h-4 w-4" /> : <Bell className="h-4 w-4" />}
        </span>
        <div>
          <div className="text-sm font-semibold">Push notifications</div>
          <div className="text-xs text-muted-foreground">
            {blocked
              ? "Blocked in your browser settings — allow Billsline to get alerts"
              : "Always on — credit alerts and transaction updates"}
          </div>
        </div>
      </div>
      <div className="flex items-center gap-2">
        {contextBlock && contextBlock !== "disabled" ? (
          <Button size="sm" className="h-8 shrink-0" onClick={openStandaloneApp}>
            <ExternalLink className="mr-1.5 h-3.5 w-3.5" />
            Open app
          </Button>
        ) : busy ? (
          <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
        ) : (
          <span className="rounded-full bg-primary/10 px-2 py-1 text-[10px] font-semibold uppercase tracking-wide text-primary">
            Always on
          </span>
        )}
      </div>
    </div>
  );
}


/** Home-screen install prompt (Android/desktop); iOS gets guidance text. */
export function InstallAppRow() {
  const [deferred, setDeferred] = useState<null | (Event & { prompt: () => Promise<void> })>(null);
  const [installed, setInstalled] = useState(false);

  useEffect(() => {
    const onPrompt = (e: Event) => {
      e.preventDefault();
      setDeferred(e as Event & { prompt: () => Promise<void> });
    };
    const onInstalled = () => setInstalled(true);
    window.addEventListener("beforeinstallprompt", onPrompt);
    window.addEventListener("appinstalled", onInstalled);
    if (window.matchMedia("(display-mode: standalone)").matches) setInstalled(true);
    return () => {
      window.removeEventListener("beforeinstallprompt", onPrompt);
      window.removeEventListener("appinstalled", onInstalled);
    };
  }, []);

  if (installed) return null;

  return (
    <div className="flex items-center justify-between gap-3 px-4 py-3">
      <div className="flex items-center gap-3">
        <span className="grid h-9 w-9 place-items-center rounded-full bg-primary/10 text-primary">
          <Download className="h-4 w-4" />
        </span>
        <div>
          <div className="text-sm font-semibold">Install Billsline app</div>
          <div className="text-xs text-muted-foreground">
            {deferred ? "Add Billsline to your home screen" : "Use your browser menu → Add to Home Screen"}
          </div>
        </div>
      </div>
      {deferred && (
        <Button size="sm" className="h-8" onClick={() => void deferred.prompt()}>
          Install
        </Button>
      )}
    </div>
  );
}
