"use client";

import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { useSession } from "next-auth/react";
import Link from "next/link";
import type { Route } from "next";
import { motion, useAnimationControls } from "framer-motion";
import { useAnchoredOverlay } from "~/hooks/useAnchoredOverlay.js";
import { trpc } from "~/lib/trpc/client.js";

function relativeTime(date: Date): string {
  const now = Date.now();
  const diff = now - date.getTime();
  const seconds = Math.floor(diff / 1000);
  if (seconds < 60) return "just now";
  const minutes = Math.floor(seconds / 60);
  if (minutes < 60) return `${minutes}m ago`;
  const hours = Math.floor(minutes / 60);
  if (hours < 24) return `${hours}h ago`;
  const days = Math.floor(hours / 24);
  if (days < 30) return `${days}d ago`;
  const months = Math.floor(days / 30);
  return `${months}mo ago`;
}

type TabKey = "all" | "tasks" | "reminders";

export function NotificationBell() {
  const [open, setOpen] = useState(false);
  const [activeTab, setActiveTab] = useState<TabKey>("all");
  const bellRef = useRef<HTMLButtonElement>(null);
  const { data: session, status } = useSession();
  const isAuthenticated = status === "authenticated" && !!session?.user?.email;
  const { panelRef, position, handleOpenChange } = useAnchoredOverlay<HTMLButtonElement>({
    open,
    onClose: () => setOpen(false),
    side: "right",
    crossAlign: "start",
    triggerRef: bellRef,
  });

  const badgeControls = useAnimationControls();
  const prevUnreadRef = useRef<number | null>(null);

  const utils = trpc.useUtils();

  const { data: unreadCount = 0 } = trpc.notification.unreadCount.useQuery(undefined, {
    enabled: isAuthenticated,
    refetchInterval: 60_000,
    retry: false,
  });

  const { data: taskCounts } = trpc.notification.taskCounts.useQuery(undefined, {
    enabled: isAuthenticated,
    refetchInterval: 60_000,
    retry: false,
  });

  // Bounce badge when unread count increases
  useEffect(() => {
    if (prevUnreadRef.current !== null && unreadCount > prevUnreadRef.current) {
      void badgeControls.start({
        scale: [1, 1.3, 1],
        transition: { duration: 0.3, ease: "easeInOut" },
      });
    }
    prevUnreadRef.current = unreadCount;
  }, [unreadCount, badgeControls]);

  const openTaskCount = (taskCounts?.open ?? 0) + (taskCounts?.inProgress ?? 0);

  const { data: notifications = [] } = trpc.notification.list.useQuery(
    { limit: 20 },
    { enabled: open && isAuthenticated && activeTab === "all", retry: false },
  );

  const { data: tasks = [] } = trpc.notification.listTasks.useQuery(
    { status: "OPEN", limit: 10 },
    { enabled: open && isAuthenticated && activeTab === "tasks", retry: false },
  );

  const { data: reminders = [] } = trpc.notification.listReminders.useQuery(
    { limit: 10 },
    { enabled: open && isAuthenticated && activeTab === "reminders", retry: false },
  );

  const markRead = trpc.notification.markRead.useMutation({
    onSuccess: () => {
      void utils.notification.unreadCount.invalidate();
      void utils.notification.list.invalidate();
    },
  });

  const updateTaskStatus = trpc.notification.updateTaskStatus.useMutation({
    onSuccess: () => {
      void utils.notification.taskCounts.invalidate();
      void utils.notification.listTasks.invalidate();
      void utils.notification.unreadCount.invalidate();
      void utils.notification.list.invalidate();
    },
  });

  function handleMarkAllRead() {
    if (!isAuthenticated) return;
    markRead.mutate({});
  }

  function handleMarkOne(id: string) {
    if (!isAuthenticated) return;
    markRead.mutate({ id });
  }

  function handleTaskAction(id: string, taskStatus: string) {
    updateTaskStatus.mutate({ id, status: taskStatus as "OPEN" | "IN_PROGRESS" | "DONE" | "DISMISSED" });
  }

  const tabs: { key: TabKey; label: string }[] = [
    { key: "all", label: "All" },
    { key: "tasks", label: "Tasks" },
    { key: "reminders", label: "Reminders" },
  ];

  return (
    <div className="relative">
      {/* Bell button */}
      <button
        ref={bellRef}
        type="button"
        onClick={() => {
          setOpen((current) => {
            const nextOpen = !current;
            handleOpenChange(nextOpen);
            return nextOpen;
          });
        }}
        className="relative p-2 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors"
        aria-label="Notifications"
      >
        <svg
          className="w-5 h-5"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
          aria-hidden="true"
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeWidth={2}
            d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"
          />
        </svg>
        {/* Unread notification badge (red) */}
        {unreadCount > 0 && (
          <motion.span
            animate={badgeControls}
            className="absolute top-0.5 right-0.5 flex items-center justify-center min-w-[16px] h-4 px-1 text-[10px] font-bold text-white bg-red-500 rounded-full leading-none"
          >
            {unreadCount > 99 ? "99+" : unreadCount}
          </motion.span>
        )}
        {/* Task count badge (orange) */}
        {openTaskCount > 0 && (
          <span className="absolute -bottom-0.5 right-0.5 flex items-center justify-center min-w-[14px] h-3.5 px-0.5 text-[9px] font-bold text-white bg-orange-500 rounded-full leading-none">
            {openTaskCount > 99 ? "99+" : openTaskCount}
          </span>
        )}
      </button>

      {/* Dropdown panel — rendered via portal to escape sidebar overflow */}
      {open && createPortal(
        <motion.div
          ref={panelRef}
          initial={{ opacity: 0, scaleY: 0.95, scaleX: 0.98 }}
          animate={{ opacity: 1, scaleY: 1, scaleX: 1 }}
          transition={{ duration: 0.15, ease: "easeOut" }}
          className="fixed w-96 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg z-[9999] overflow-hidden origin-top"
          style={{ top: position.top, left: position.left }}
        >
          {/* Header */}
          <div className="flex items-center justify-between px-4 py-3 border-b border-gray-100 dark:border-gray-800">
            <span className="text-sm font-semibold text-gray-900 dark:text-gray-50">
              Notifications
            </span>
            {unreadCount > 0 && activeTab === "all" && (
              <button
                type="button"
                onClick={handleMarkAllRead}
                disabled={markRead.isPending}
                className="text-xs text-brand-600 dark:text-brand-400 hover:underline disabled:opacity-50"
              >
                Mark all read
              </button>
            )}
          </div>

          {/* Tabs */}
          <div className="flex border-b border-gray-100 dark:border-gray-800">
            {tabs.map((tab) => (
              <button
                key={tab.key}
                type="button"
                onClick={() => setActiveTab(tab.key)}
                className={`flex-1 px-3 py-2 text-xs font-medium transition-colors ${
                  activeTab === tab.key
                    ? "text-brand-600 dark:text-brand-400 border-b-2 border-brand-600 dark:border-brand-400"
                    : "text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
                }`}
              >
                {tab.label}
                {tab.key === "tasks" && openTaskCount > 0 && (
                  <span className="ml-1 inline-flex items-center justify-center min-w-[16px] h-4 px-1 text-[10px] font-bold text-white bg-orange-500 rounded-full">
                    {openTaskCount}
                  </span>
                )}
              </button>
            ))}
          </div>

          {/* Content */}
          <div className="max-h-80 overflow-y-auto divide-y divide-gray-50 dark:divide-gray-800">
            {activeTab === "all" && (
              <>
                {notifications.length === 0 ? (
                  <div className="px-4 py-8 text-center text-sm text-gray-400 dark:text-gray-500">
                    No notifications yet
                  </div>
                ) : (
                  notifications.map((n) => {
                    const isUnread = n.readAt === null;
                    return (
                      <button
                        key={n.id}
                        type="button"
                        onClick={() => {
                          if (isUnread) handleMarkOne(n.id);
                        }}
                        className={`w-full text-left px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors ${
                          isUnread ? "bg-blue-50/60 dark:bg-blue-900/10" : ""
                        }`}
                      >
                        <div className="flex items-start gap-2">
                          {isUnread && (
                            <span className="mt-1.5 w-2 h-2 rounded-full bg-blue-500 shrink-0" />
                          )}
                          <div className={isUnread ? "" : "ml-4"}>
                            <p className="text-sm font-medium text-gray-900 dark:text-gray-100 leading-snug">
                              {n.title}
                            </p>
                            {n.body && (
                              <p className="mt-0.5 text-xs text-gray-500 dark:text-gray-400 line-clamp-2">
                                {n.body}
                              </p>
                            )}
                            <p className="mt-1 text-xs text-gray-400 dark:text-gray-500">
                              {relativeTime(new Date(n.createdAt))}
                            </p>
                          </div>
                        </div>
                      </button>
                    );
                  })
                )}
              </>
            )}

            {activeTab === "tasks" && (
              <>
                {tasks.length === 0 ? (
                  <div className="px-4 py-8 text-center text-sm text-gray-400 dark:text-gray-500">
                    No open tasks
                  </div>
                ) : (
                  tasks.map((t) => (
                    <div key={t.id} className="px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
                      <div className="flex items-start justify-between gap-2">
                        <div className="flex-1 min-w-0">
                          <p className="text-sm font-medium text-gray-900 dark:text-gray-100 leading-snug truncate">
                            {t.title}
                          </p>
                          {t.dueDate && (
                            <p className={`mt-0.5 text-xs ${new Date(t.dueDate).getTime() < Date.now() ? "text-red-600 dark:text-red-400 font-semibold" : "text-gray-400 dark:text-gray-500"}`}>
                              Due: {new Date(t.dueDate).toLocaleDateString("en-GB")}
                            </p>
                          )}
                        </div>
                        <div className="flex items-center gap-1 shrink-0">
                          <button
                            type="button"
                            onClick={() => handleTaskAction(t.id, "DONE")}
                            disabled={updateTaskStatus.isPending}
                            className="p-1 text-green-600 hover:bg-green-100 dark:hover:bg-green-900/30 rounded transition-colors"
                            title="Mark as Done"
                          >
                            <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
                            </svg>
                          </button>
                          <button
                            type="button"
                            onClick={() => handleTaskAction(t.id, "DISMISSED")}
                            disabled={updateTaskStatus.isPending}
                            className="p-1 text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 rounded transition-colors"
                            title="Dismiss"
                          >
                            <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                            </svg>
                          </button>
                        </div>
                      </div>
                    </div>
                  ))
                )}
              </>
            )}

            {activeTab === "reminders" && (
              <>
                {reminders.length === 0 ? (
                  <div className="px-4 py-8 text-center text-sm text-gray-400 dark:text-gray-500">
                    No reminders
                  </div>
                ) : (
                  reminders.map((r) => (
                    <div key={r.id} className="px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
                      <p className="text-sm font-medium text-gray-900 dark:text-gray-100 leading-snug">
                        {r.title}
                      </p>
                      {r.body && (
                        <p className="mt-0.5 text-xs text-gray-500 dark:text-gray-400 line-clamp-1">
                          {r.body}
                        </p>
                      )}
                      <p className="mt-1 text-xs text-gray-400 dark:text-gray-500">
                        {r.nextRemindAt
                          ? new Date(r.nextRemindAt).toLocaleDateString("en-GB", {
                              day: "2-digit",
                              month: "short",
                              year: "numeric",
                              hour: "2-digit",
                              minute: "2-digit",
                            })
                          : relativeTime(new Date(r.createdAt))}
                        {r.recurrence && (
                          <span className="ml-2 text-brand-500 dark:text-brand-400">{r.recurrence}</span>
                        )}
                      </p>
                    </div>
                  ))
                )}
              </>
            )}
          </div>

          {/* Footer */}
          <div className="border-t border-gray-100 dark:border-gray-800 px-4 py-2">
            <Link
              href={"/notifications" as Route}
              onClick={() => setOpen(false)}
              className="block text-center text-xs font-medium text-brand-600 dark:text-brand-400 hover:underline"
            >
              View all &rarr;
            </Link>
          </div>
        </motion.div>,
        document.body,
      )}
    </div>
  );
}
