"use client";

import { useEffect, useMemo, useState } from "react";
import { AppShell } from "@/components/app-shell";
import { apiFetch } from "@/lib/api";

type NotificationPreference = {
  emailEnabled: boolean;
  pushEnabled: boolean;
  minSeverity: "info" | "warning" | "critical";
};

type LedgerNotification = {
  id: string;
  type: string;
  severity: "info" | "warning" | "critical";
  title: string;
  body: string;
  channels: string[];
  readAt?: string | null;
  createdAt: string;
};

type VapidStatus = {
  enabled: boolean;
  publicKey: string | null;
};

function urlBase64ToUint8Array(base64String: string) {
  const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
  const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
  const rawData = window.atob(base64);
  const outputArray = new Uint8Array(rawData.length);
  for (let i = 0; i < rawData.length; i += 1) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

export default function NotificationsPage() {
  const [notifications, setNotifications] = useState<LedgerNotification[]>([]);
  const [preferences, setPreferences] = useState<NotificationPreference>({
    emailEnabled: true,
    pushEnabled: false,
    minSeverity: "info",
  });
  const [vapid, setVapid] = useState<VapidStatus>({ enabled: false, publicKey: null });
  const [status, setStatus] = useState("");
  const [loading, setLoading] = useState(true);

  const unreadCount = useMemo(() => notifications.filter((item) => !item.readAt).length, [notifications]);

  const load = async () => {
    setLoading(true);
    const [listRes, prefRes, vapidRes] = await Promise.all([
      apiFetch<LedgerNotification[]>("/api/notifications"),
      apiFetch<NotificationPreference>("/api/notifications/preferences"),
      apiFetch<VapidStatus>("/api/notifications/vapid-public-key"),
    ]);
    if (!listRes.error) setNotifications(listRes.data ?? []);
    if (!prefRes.error && prefRes.data) setPreferences(prefRes.data);
    if (!vapidRes.error && vapidRes.data) setVapid(vapidRes.data);
    setLoading(false);
  };

  useEffect(() => {
    load();
  }, []);

  const updatePreferences = async (patch: Partial<NotificationPreference>) => {
    const next = { ...preferences, ...patch };
    setPreferences(next);
    const res = await apiFetch<NotificationPreference>("/api/notifications/preferences", {
      method: "PATCH",
      body: JSON.stringify(patch),
    });
    if (res.error) {
      setStatus(res.error.message ?? "Could not update notification preferences.");
      return;
    }
    if (res.data) setPreferences(res.data);
    setStatus("Notification preferences updated.");
  };

  const enablePush = async () => {
    setStatus("");
    if (!vapid.enabled || !vapid.publicKey) {
      setStatus("Push notifications need VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY on the backend.");
      return;
    }
    if (!("serviceWorker" in navigator) || !("PushManager" in window)) {
      setStatus("This browser does not support web push notifications.");
      return;
    }

    const permission = await Notification.requestPermission();
    if (permission !== "granted") {
      setStatus("Browser notification permission was not granted.");
      return;
    }

    const registration = await navigator.serviceWorker.register("/sw.js");
    const existing = await registration.pushManager.getSubscription();
    const subscription = existing ?? await registration.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: urlBase64ToUint8Array(vapid.publicKey),
    });

    const res = await apiFetch("/api/notifications/push-subscriptions", {
      method: "POST",
      body: JSON.stringify(subscription.toJSON()),
    });
    if (res.error) {
      setStatus(res.error.message ?? "Could not save push subscription.");
      return;
    }
    setPreferences((prev) => ({ ...prev, pushEnabled: true }));
    setStatus("Push notifications enabled for this browser.");
  };

  const sendTest = async () => {
    setStatus("Sending test notification...");
    const res = await apiFetch("/api/notifications/test", { method: "POST" });
    if (res.error) {
      setStatus(res.error.message ?? "Test notification failed.");
      return;
    }
    setStatus("Test notification sent.");
    await load();
  };

  const markRead = async (id: string) => {
    const res = await apiFetch(`/api/notifications/${id}/read`, { method: "PATCH" });
    if (!res.error) {
      setNotifications((items) => items.map((item) => item.id === id ? { ...item, readAt: new Date().toISOString() } : item));
    }
  };

  const markAllRead = async () => {
    const res = await apiFetch("/api/notifications/read-all", { method: "POST" });
    if (!res.error) {
      const now = new Date().toISOString();
      setNotifications((items) => items.map((item) => ({ ...item, readAt: item.readAt ?? now })));
    }
  };

  const inputCls = "mt-2 w-full rounded-xl border border-border bg-background/50 px-4 py-2 text-sm text-foreground focus:border-primary focus:ring-primary focus:outline-none";

  return (
    <AppShell title="Notifications" subtitle="Manage in-app, SMTP email, and browser push alerts.">
      <div className="space-y-6">
        <div className="grid gap-4 lg:grid-cols-3">
          <section className="rounded-xl border border-border bg-secondary/10 p-6">
            <p className="text-sm font-bold text-foreground">SMTP Email</p>
            <p className="mt-1 text-xs text-muted-foreground">Send important LedgerOne alerts through the configured SMTP transport.</p>
            <label className="mt-4 flex items-center gap-2 text-sm text-foreground">
              <input
                type="checkbox"
                checked={preferences.emailEnabled}
                onChange={(event) => updatePreferences({ emailEnabled: event.target.checked })}
                className="rounded border-border text-primary focus:ring-primary"
              />
              Email alerts enabled
            </label>
          </section>

          <section className="rounded-xl border border-border bg-secondary/10 p-6">
            <p className="text-sm font-bold text-foreground">Browser Push</p>
            <p className="mt-1 text-xs text-muted-foreground">
              {vapid.enabled ? "Register this browser for web push alerts." : "Backend VAPID keys are not configured."}
            </p>
            <button
              onClick={enablePush}
              disabled={!vapid.enabled}
              className="mt-4 w-full rounded-lg bg-primary py-2.5 px-4 text-sm font-bold text-primary-foreground hover:bg-primary/90 transition-all disabled:opacity-50"
            >
              {preferences.pushEnabled ? "Refresh Push Registration" : "Enable Push"}
            </button>
          </section>

          <section className="rounded-xl border border-border bg-secondary/10 p-6">
            <p className="text-sm font-bold text-foreground">Delivery Threshold</p>
            <p className="mt-1 text-xs text-muted-foreground">Email and push delivery only run at or above this severity.</p>
            <select
              value={preferences.minSeverity}
              onChange={(event) => updatePreferences({ minSeverity: event.target.value as NotificationPreference["minSeverity"] })}
              className={inputCls}
            >
              <option value="info">Info and above</option>
              <option value="warning">Warning and above</option>
              <option value="critical">Critical only</option>
            </select>
          </section>
        </div>

        <div className="rounded-xl border border-border bg-secondary/10 p-6">
          <div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
            <div>
              <p className="text-sm font-bold text-foreground">Notification Center</p>
              <p className="mt-1 text-xs text-muted-foreground">{unreadCount} unread alert{unreadCount === 1 ? "" : "s"}</p>
            </div>
            <div className="flex flex-wrap gap-2">
              <button onClick={sendTest} className="rounded-lg bg-primary px-4 py-2 text-sm font-bold text-primary-foreground hover:bg-primary/90">
                Send Test
              </button>
              <button onClick={markAllRead} className="rounded-lg border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-secondary/40">
                Mark All Read
              </button>
            </div>
          </div>

          {status && <p className="mt-4 rounded-lg border border-border bg-background/60 px-4 py-3 text-sm text-muted-foreground">{status}</p>}

          <div className="mt-6 divide-y divide-border">
            {loading && <p className="py-8 text-sm text-muted-foreground">Loading notifications...</p>}
            {!loading && notifications.length === 0 && <p className="py-8 text-sm text-muted-foreground">No notifications yet.</p>}
            {!loading && notifications.map((item) => (
              <article key={item.id} className="py-4">
                <div className="flex flex-col gap-3 md:flex-row md:items-start md:justify-between">
                  <div>
                    <div className="flex flex-wrap items-center gap-2">
                      {!item.readAt && <span className="h-2 w-2 rounded-full bg-primary" />}
                      <p className="text-sm font-bold text-foreground">{item.title}</p>
                      <span className="rounded-full border border-border px-2 py-0.5 text-xs text-muted-foreground">{item.severity}</span>
                    </div>
                    <p className="mt-1 text-sm text-muted-foreground">{item.body}</p>
                    <p className="mt-2 text-xs text-muted-foreground">
                      {new Date(item.createdAt).toLocaleString()} · {item.channels.join(", ") || "in_app"}
                    </p>
                  </div>
                  {!item.readAt && (
                    <button onClick={() => markRead(item.id)} className="rounded-lg border border-border px-3 py-1.5 text-xs font-medium text-foreground hover:bg-secondary/40">
                      Mark Read
                    </button>
                  )}
                </div>
              </article>
            ))}
          </div>
        </div>
      </div>
    </AppShell>
  );
}
