"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import Echo from "laravel-echo";
import Pusher from "pusher-js";
import {
  AlertCircle,
  Bell,
  CheckCircle2,
  Clock,
  Info,
  Loader2,
  Wifi,
  WifiOff,
} from "lucide-react";
import { formatDistanceToNow } from "date-fns";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { API_CONFIG, REVERB_CONFIG, TOKEN_CONFIG } from "@/core/api/config";
import { notificationsService } from "@/core/api/services/notifications";
import { useAdminAuth } from "@/roles/admin/components/admin-auth-provider";
import { notifyAdminNotificationCountChanged } from "./admin-notification-bell";
import type {
  AdminNotification,
  NotificationCreatedEvent,
} from "@/core/api/services/notifications";

declare global {
  interface Window {
    Pusher: typeof Pusher;
  }
}

type NotificationTone = "success" | "warning" | "info";

const toneIcons = {
  success: CheckCircle2,
  warning: AlertCircle,
  info: Info,
};

function getStoredToken() {
  if (typeof window === "undefined") return null;
  return localStorage.getItem(TOKEN_CONFIG.STORAGE_KEY);
}

function getNotificationMessage(notification: AdminNotification) {
  return notification.message ?? notification.notification_message ?? null;
}

function getNotificationTone(notification: AdminNotification): NotificationTone {
  const message = getNotificationMessage(notification);
  const typeTitle = message?.notification_type?.title?.toLowerCase() ?? "";
  const title = message?.title?.toLowerCase() ?? "";

  if (
    typeTitle.includes("success") ||
    title.includes("registered") ||
    title.includes("created") ||
    title.includes("completed")
  ) {
    return "success";
  }

  if (
    typeTitle.includes("warning") ||
    title.includes("blocked") ||
    title.includes("rejected")
  ) {
    return "warning";
  }

  return "info";
}

function formatNotificationTime(value: string | null) {
  if (!value) return "Just now";

  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "Just now";

  return formatDistanceToNow(date, { addSuffix: true });
}

function formatDetailLabel(key: string) {
  return key
    .replace(/_/g, " ")
    .replace(/\b\w/g, (letter) => letter.toUpperCase());
}

function formatDetailValue(value: unknown) {
  if (value === null || value === undefined || value === "") return "-";
  if (typeof value === "object") return JSON.stringify(value);
  return String(value);
}

function getNotificationDetails(notification: AdminNotification) {
  const rawDetails = notification.json_data;

  if (!rawDetails) return [];

  try {
    const details =
      typeof rawDetails === "string" ? JSON.parse(rawDetails) : rawDetails;

    if (!details || typeof details !== "object" || Array.isArray(details)) {
      return [];
    }

    return Object.entries(details);
  } catch {
    return [];
  }
}

function getNotificationPerson(notification: AdminNotification) {
  const details = Object.fromEntries(getNotificationDetails(notification));
  const firstName = formatDetailValue(details.first_name);
  const lastName = formatDetailValue(details.last_name);
  const email = formatDetailValue(details.email);
  const fullName = [firstName, lastName]
    .filter((value) => value && value !== "-")
    .join(" ");

  return {
    name: fullName || email || "Unknown user",
    email: email !== "-" ? email : null,
  };
}

function countUnreadNotifications(notifications: AdminNotification[]) {
  return notifications.filter((notification) => notification.status === "new")
    .length;
}

function toAbsoluteAuthEndpoint(endpoint: string) {
  if (endpoint.startsWith("http://") || endpoint.startsWith("https://")) {
    return endpoint;
  }

  return `${new URL(API_CONFIG.BASE_URL).origin}${endpoint}`;
}

export function AdminNotificationsClient() {
  const { currentUser, isLoading: isUserLoading } = useAdminAuth();
  const [notifications, setNotifications] = useState<AdminNotification[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [isConnected, setIsConnected] = useState(false);
  const [selectedNotification, setSelectedNotification] =
    useState<AdminNotification | null>(null);
  const [actionError, setActionError] = useState<string | null>(null);
  const [pendingAction, setPendingAction] = useState<
    "mark-all" | "delete-all" | "delete-one" | null
  >(null);
  const unreadCountRef = useRef(0);

  const unreadCount = useMemo(
    () => countUnreadNotifications(notifications),
    [notifications]
  );

  useEffect(() => {
    unreadCountRef.current = unreadCount;
  }, [unreadCount]);

  const fetchNotifications = useCallback(async () => {
    try {
      setError(null);
      setIsLoading(true);
      const paginator = await notificationsService.list();
      setNotifications(paginator.data);
      notifyAdminNotificationCountChanged(
        countUnreadNotifications(paginator.data)
      );
    } catch (err) {
      const message =
        err instanceof Error ? err.message : "Failed to load notifications.";
      setError(message);
    } finally {
      setIsLoading(false);
    }
  }, []);

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

  const openNotification = useCallback(async (notification: AdminNotification) => {
    setActionError(null);
    setSelectedNotification({ ...notification, status: "read" });

    if (notification.status !== "new") return;

    setNotifications((current) =>
      current.map((item) =>
        item.id === notification.id ? { ...item, status: "read" } : item
      )
    );
    notifyAdminNotificationCountChanged(Math.max(unreadCount - 1, 0));

    try {
      await notificationsService.markAsRead(notification.id);
    } catch (err) {
      const message =
        err instanceof Error ? err.message : "Failed to mark notification read.";
      setActionError(message);
      setNotifications((current) =>
        current.map((item) =>
          item.id === notification.id ? { ...item, status: "new" } : item
        )
      );
      setSelectedNotification(notification);
      notifyAdminNotificationCountChanged(unreadCount);
    }
  }, [unreadCount]);

  const markAllAsRead = useCallback(async () => {
    setActionError(null);
    setPendingAction("mark-all");

    const previousNotifications = notifications;
    setNotifications((current) =>
      current.map((notification) => ({ ...notification, status: "read" }))
    );
    notifyAdminNotificationCountChanged(0);

    try {
      await notificationsService.bulkMarkAsRead();
    } catch (err) {
      const message =
        err instanceof Error ? err.message : "Failed to mark notifications read.";
      setActionError(message);
      setNotifications(previousNotifications);
      notifyAdminNotificationCountChanged(
        countUnreadNotifications(previousNotifications)
      );
    } finally {
      setPendingAction(null);
    }
  }, [notifications]);

  const deleteAllNotifications = useCallback(async () => {
    setActionError(null);
    setPendingAction("delete-all");

    const previousNotifications = notifications;
    setNotifications([]);
    setSelectedNotification(null);
    notifyAdminNotificationCountChanged(0);

    try {
      await notificationsService.bulkDelete();
    } catch (err) {
      const message =
        err instanceof Error ? err.message : "Failed to delete notifications.";
      setActionError(message);
      setNotifications(previousNotifications);
      notifyAdminNotificationCountChanged(
        countUnreadNotifications(previousNotifications)
      );
    } finally {
      setPendingAction(null);
    }
  }, [notifications]);

  const deleteSelectedNotification = useCallback(async () => {
    if (!selectedNotification) return;

    setActionError(null);
    setPendingAction("delete-one");

    const notificationToDelete = selectedNotification;
    setNotifications((current) =>
      current.filter((notification) => notification.id !== notificationToDelete.id)
    );
    setSelectedNotification(null);
    notifyAdminNotificationCountChanged(
      Math.max(
        unreadCount - (notificationToDelete.status === "new" ? 1 : 0),
        0
      )
    );

    try {
      await notificationsService.delete(notificationToDelete.id);
    } catch (err) {
      const message =
        err instanceof Error ? err.message : "Failed to delete notification.";
      setActionError(message);
      setNotifications((current) => [notificationToDelete, ...current]);
      notifyAdminNotificationCountChanged(unreadCount);
    } finally {
      setPendingAction(null);
    }
  }, [selectedNotification, unreadCount]);

  useEffect(() => {
    if (isUserLoading || !currentUser?.id || !REVERB_CONFIG.APP_KEY) return;

    const token = getStoredToken();
    if (!token) {
      setIsConnected(false);
      return;
    }

    window.Pusher = Pusher;

    const echo = new Echo({
      broadcaster: "reverb",
      key: REVERB_CONFIG.APP_KEY,
      wsHost: REVERB_CONFIG.HOST,
      wsPort: REVERB_CONFIG.PORT,
      wssPort: REVERB_CONFIG.PORT,
      forceTLS: REVERB_CONFIG.SCHEME === "https",
      enabledTransports: ["ws", "wss"],
      authEndpoint: toAbsoluteAuthEndpoint(REVERB_CONFIG.AUTH_ENDPOINT),
      auth: {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      },
    });

    const connector = echo.connector as any;
    connector.pusher.connection.bind("connected", () => setIsConnected(true));
    connector.pusher.connection.bind("disconnected", () =>
      setIsConnected(false)
    );
    connector.pusher.connection.bind("error", () => setIsConnected(false));

    echo
      .private(`users.${currentUser.id}`)
      .listen(
        ".notification.created",
        (event: NotificationCreatedEvent | AdminNotification) => {
          const notification =
            "notification" in event ? event.notification : event;

          setNotifications((current) => {
            const withoutDuplicate = current.filter(
              (item) => item.id !== notification.id
            );
            const nextNotifications = [notification, ...withoutDuplicate];
            const nextUnreadCount =
              countUnreadNotifications(nextNotifications);
            unreadCountRef.current = nextUnreadCount;
            notifyAdminNotificationCountChanged(nextUnreadCount);
            return nextNotifications;
          });
        }
      );

    return () => {
      echo.leave(`users.${currentUser.id}`);
      echo.disconnect();
      setIsConnected(false);
    };
  }, [currentUser?.id, isUserLoading]);

  const selectedMessage = selectedNotification
    ? getNotificationMessage(selectedNotification)
    : null;
  const selectedPerson = selectedNotification
    ? getNotificationPerson(selectedNotification)
    : null;
  const selectedDetails = selectedNotification
    ? getNotificationDetails(selectedNotification)
    : [];
  const selectedTime = selectedNotification
    ? formatNotificationTime(selectedNotification.created_at)
    : "";

  return (
    <div className="admin-section">
      <header className="admin-page-header">
        <div className="flex items-center gap-3">
          <div className="rounded-xl bg-gradient-to-br from-primary/20 to-primary/5 p-2.5">
            <Bell className="h-5 w-5 text-primary" />
          </div>
          <div>
            <h1 className="admin-page-title">Notifications</h1>
            <p className="admin-page-description">
              Stay updated with your platform activities
            </p>
          </div>
        </div>
      </header>

      <Card className="admin-card rounded-xl border-0">
        <CardHeader className="gap-3">
          <div className="min-w-0">
            <CardTitle>All Notifications</CardTitle>
            <CardDescription>
              Recent alerts and updates from your admin panel
            </CardDescription>
          </div>
          <div className="flex w-full flex-wrap items-center justify-between gap-2">
            <div className="flex flex-wrap items-center gap-2">
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={markAllAsRead}
                disabled={unreadCount === 0 || pendingAction !== null}
              >
                {pendingAction === "mark-all"
                  ? "Updating..."
                  : "All mark as read"}
              </Button>
              <Button
                type="button"
                variant="destructive"
                size="sm"
                onClick={deleteAllNotifications}
                disabled={notifications.length === 0 || pendingAction !== null}
              >
                {pendingAction === "delete-all" ? "Deleting..." : "Delete all"}
              </Button>
            </div>
            <div className="flex flex-wrap items-center justify-end gap-2">
              <Badge variant={unreadCount ? "default" : "secondary"}>
                {unreadCount} unread
              </Badge>
              <Badge variant="outline" className="gap-1.5">
                {isConnected ? (
                  <Wifi className="h-3.5 w-3.5 text-emerald-600" />
                ) : (
                  <WifiOff className="h-3.5 w-3.5 text-muted-foreground" />
                )}
                {isConnected ? "Live" : "Offline"}
              </Badge>
            </div>
          </div>
        </CardHeader>
        <CardContent>
          {isLoading ? (
            <div className="flex min-h-48 items-center justify-center text-sm text-muted-foreground">
              <Loader2 className="mr-2 h-4 w-4 animate-spin" />
              Loading notifications
            </div>
          ) : error ? (
            <div className="rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive">
              {error}
            </div>
          ) : notifications.length === 0 ? (
            <div className="flex min-h-48 flex-col items-center justify-center rounded-lg border border-dashed text-center">
              <Bell className="h-8 w-8 text-muted-foreground" />
              <h3 className="mt-3 font-semibold">No notifications</h3>
              <p className="mt-1 text-sm text-muted-foreground">
                New admin alerts will appear here automatically.
              </p>
            </div>
          ) : (
            <div className="space-y-3">
              {notifications.map((notification) => {
                const message = getNotificationMessage(notification);
                const tone = getNotificationTone(notification);
                const Icon = toneIcons[tone];
                const isUnread = notification.status === "new";
                const person = getNotificationPerson(notification);
                const time = formatNotificationTime(notification.created_at);

                return (
                  <div
                    key={notification.id}
                    role="button"
                    tabIndex={0}
                    onClick={() => openNotification(notification)}
                    onKeyDown={(event) => {
                      if (event.key === "Enter" || event.key === " ") {
                        event.preventDefault();
                        openNotification(notification);
                      }
                    }}
                    className={cn(
                      "flex cursor-pointer items-start gap-4 rounded-lg border p-4 text-left transition-all hover:shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
                      isUnread
                        ? "border-border bg-card shadow-sm"
                        : "border-border/50 bg-muted/30"
                    )}
                  >
                    <div
                      className={cn(
                        "mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full",
                        tone === "success" && "bg-emerald-500/10",
                        tone === "warning" && "bg-amber-500/10",
                        tone === "info" && "bg-primary/10"
                      )}
                    >
                      <Icon
                        className={cn(
                          "h-4 w-4",
                          tone === "success" && "text-emerald-600",
                          tone === "warning" && "text-amber-600",
                          tone === "info" && "text-primary"
                        )}
                      />
                    </div>
                    <div className="min-w-0 flex-1">
                      <div className="mb-1 flex items-start justify-between gap-2">
                        <div className="flex min-w-0 flex-wrap items-center gap-1.5">
                          <span
                            className={cn(
                              "min-w-0 truncate text-sm font-semibold",
                              isUnread
                                ? "text-primary"
                                : "text-muted-foreground"
                            )}
                          >
                            {person.name}
                          </span>
                          {person.email && person.email !== person.name && (
                            <>
                              <span className="h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/30" />
                              <span className="min-w-0 truncate text-xs text-muted-foreground">
                                {person.email}
                              </span>
                            </>
                          )}
                        </div>
                        <div className="flex shrink-0 items-center gap-2 pl-2">
                          {isUnread && (
                            <span
                              className="h-2 w-2 shrink-0 rounded-full bg-primary"
                              aria-label="Unread"
                            />
                          )}
                        </div>
                      </div>
                      <h3
                        className={cn(
                          "mb-1 text-sm font-medium",
                          isUnread
                            ? "text-foreground"
                            : "text-muted-foreground"
                        )}
                      >
                        {message?.title ?? "Notification"}
                      </h3>
                      <p className="mb-2 text-sm text-gray-600">
                        {message?.description ?? "You have a new notification."}
                      </p>
                      <div className="flex items-center gap-1.5 text-xs text-muted-foreground">
                        <Clock className="h-3.5 w-3.5" />
                        {time}
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
          {actionError && (
            <div className="mt-3 rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive">
              {actionError}
            </div>
          )}
        </CardContent>
      </Card>

      <Dialog
        open={Boolean(selectedNotification)}
        onOpenChange={(open) => {
          if (!open) setSelectedNotification(null);
        }}
      >
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle className="pr-8">
              {selectedMessage?.title ?? "Notification"}
            </DialogTitle>
            <DialogDescription>
              {selectedPerson?.name}
              {selectedPerson?.email && selectedPerson.email !== selectedPerson.name
                ? ` - ${selectedPerson.email}`
                : ""}
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            <p className="text-sm leading-6 text-foreground">
              {selectedMessage?.description ?? "You have a new notification."}
            </p>

            {selectedDetails.length > 0 && (
              <div className="rounded-md border bg-muted/40 p-3">
                <div className="grid gap-2 text-sm">
                  {selectedDetails.map(([key, value]) => (
                    <div
                      key={key}
                      className="grid grid-cols-[96px_minmax(0,1fr)] gap-3"
                    >
                      <span className="text-muted-foreground">
                        {formatDetailLabel(key)}
                      </span>
                      <span className="min-w-0 break-words font-medium">
                        {formatDetailValue(value)}
                      </span>
                    </div>
                  ))}
                </div>
              </div>
            )}

            <div className="flex items-center gap-1.5 text-xs text-muted-foreground">
              <Clock className="h-3.5 w-3.5" />
              {selectedTime}
            </div>
          </div>
          <DialogFooter>
            <Button
              type="button"
              variant="destructive"
              onClick={deleteSelectedNotification}
              disabled={pendingAction === "delete-one"}
            >
              {pendingAction === "delete-one" ? "Deleting..." : "Delete message"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
