"use client";

import { AnimatePresence, motion } from "framer-motion";
import { Bell, CheckCheck } from "lucide-react";
import moment from "moment";
import { useRouter } from "next/navigation";
import { useEffect, useRef, useState } from "react";
import { NOTIFICATION_CODE, NotificationCode } from "@/api/constant";
import {
  useGetNotificationListQuery,
  useGetNotificationUnreadCountQuery,
  useMarkNotificationReadMutation,
} from "@/api/notification.api";
import { INotificationLog } from "@/api/types/notification";

interface NotificationStyle {
  wrapper: string;
  pill: string;
  label: string;
  verdict: string;
  accent: string;
}

const DEFAULT_STYLE: NotificationStyle = {
  wrapper: "bg-gray-50",
  pill: "bg-gray-100 text-gray-700",
  label: "Update",
  verdict: "You have a new notification",
  accent: "bg-gray-400",
};

const STATUS_STYLES: Record<NotificationCode, NotificationStyle> = {
  [NOTIFICATION_CODE.QUESTION_APPROVED]: {
    wrapper: "bg-green-50",
    pill: "bg-green-100 text-green-700",
    label: "Approved",
    verdict: "Your question was approved",
    accent: "bg-green-500",
  },
  [NOTIFICATION_CODE.ANSWER_APPROVED]: {
    wrapper: "bg-green-50",
    pill: "bg-green-100 text-green-700",
    label: "Approved",
    verdict: "Your answer was approved",
    accent: "bg-green-500",
  },
  [NOTIFICATION_CODE.QUESTION_GOOD]: {
    wrapper: "bg-amber-50",
    pill: "bg-amber-100 text-amber-700",
    label: "Good Question",
    verdict: "Your question was marked as good",
    accent: "bg-amber-500",
  },
  [NOTIFICATION_CODE.ANSWER_FEATURED]: {
    wrapper: "bg-violet-50",
    pill: "bg-violet-100 text-violet-700",
    label: "Featured",
    verdict: "Your answer was featured",
    accent: "bg-violet-500",
  },
  [NOTIFICATION_CODE.REQUEST_ANSWER]: {
    wrapper: "bg-sky-50",
    pill: "bg-sky-100 text-sky-700",
    label: "Answer Requested",
    verdict: "Your answer was requested",
    accent: "bg-sky-500",
  },
  [NOTIFICATION_CODE.ANSWER_REJECTED]: {
    wrapper: "bg-rose-50",
    pill: "bg-rose-100 text-rose-700",
    label: "Rejected",
    verdict: "Your answer was rejected",
    accent: "bg-rose-500",
  },
  [NOTIFICATION_CODE.QUESTION_REJECTED]: {
    wrapper: "bg-rose-50",
    pill: "bg-rose-100 text-rose-700",
    label: "Rejected",
    verdict: "Your question was rejected",
    accent: "bg-rose-500",
  },
};

const getStyle = (code: string): NotificationStyle =>
  STATUS_STYLES[code as NotificationCode] ?? DEFAULT_STYLE;

const DISCUSSION_NAV_CODES: string[] = [
  NOTIFICATION_CODE.QUESTION_APPROVED,
  NOTIFICATION_CODE.ANSWER_APPROVED,
  NOTIFICATION_CODE.QUESTION_GOOD,
  NOTIFICATION_CODE.ANSWER_FEATURED,
  NOTIFICATION_CODE.REQUEST_ANSWER,
];

const stripHtml = (html?: string): string =>
  (html ?? "").replace(/<[^>]*>/g, "").trim();

interface NotificationsProps {
  isLightPage?: boolean;
}

export default function Notifications({
  isLightPage = false,
}: NotificationsProps) {
  const [isOpen, setIsOpen] = useState(false);
  const containerRef = useRef<HTMLDivElement>(null);
  const router = useRouter();

  const { data: listData, isLoading } = useGetNotificationListQuery({
    page: 1,
    perPage: 30,
  });
  const { data: unreadData } = useGetNotificationUnreadCountQuery();
  const [markNotificationRead] = useMarkNotificationReadMutation();

  const notifications: INotificationLog[] = listData?.data ?? [];
  const unreadCount = unreadData?.unreadCount ?? 0;

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        isOpen &&
        containerRef.current &&
        !containerRef.current.contains(event.target as Node)
      ) {
        setIsOpen(false);
      }
    };

    if (isOpen) {
      document.addEventListener("click", handleClickOutside);
    }
    return () => document.removeEventListener("click", handleClickOutside);
  }, [isOpen]);

  const handleNotificationClick = (item: INotificationLog) => {
    if (!item.isRead) markNotificationRead(item.id);

    const code = item.notification?.code ?? "";
    const slug = item.replacements?.data?.code;
    if (DISCUSSION_NAV_CODES.includes(code) && slug) {
      setIsOpen(false);
      router.push(`/discussion/${slug}`);
      return;
    }

    if (code === NOTIFICATION_CODE.ANSWER_REJECTED) {
      setIsOpen(false);
      router.push("/content?tab=answers&filterType=rejected");
      return;
    }

    if (code === NOTIFICATION_CODE.QUESTION_REJECTED) {
      setIsOpen(false);
      router.push("/content?tab=questions&filterType=rejected");
    }
  };

  const handleMarkAllAsRead = () => {
    notifications
      .filter((n) => !n.isRead)
      .forEach((n) => markNotificationRead(n.id));
  };

  return (
    <div className="relative" ref={containerRef}>
      <button
        type="button"
        aria-label="Notifications"
        onClick={(e) => {
          e.stopPropagation();
          setIsOpen((v) => !v);
        }}
        className="relative h-9 w-9 flex items-center justify-center rounded-full hover:bg-gray-100 transition-colors cursor-pointer"
      >
        <Bell className="h-5 w-5 text-gray-500" />
        {unreadCount > 0 && (
          <span className="absolute top-0.5 right-0.5 min-w-[17px] h-[17px] px-1 flex items-center justify-center rounded-full bg-red-500 text-white text-[10px] font-bold leading-none">
            {unreadCount > 9 ? "9+" : unreadCount}
          </span>
        )}
      </button>

      <AnimatePresence>
        {isOpen && (
          <motion.div
            initial={{ opacity: 0, y: 10 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: 10 }}
            transition={{ duration: 0.2 }}
            className="fixed left-3 right-3 top-17 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:mt-2 sm:w-80 bg-white rounded-2xl shadow-xl border border-gray-100 z-60 overflow-hidden flex flex-col"
            style={{ maxHeight: "min(70vh, 420px)" }}
          >
            <div className="relative bg-white flex flex-col overflow-hidden z-10">
              <div className="self-stretch px-4 py-3 bg-white flex justify-between items-center border-b border-gray-100">
                <div className="text-sm font-bold text-gray-900">
                  Notifications
                </div>
                {/* {unreadCount > 0 && (
                  <button
                    type="button"
                    onClick={handleMarkAllAsRead}
                    title="Mark all as read"
                    className="h-7 w-7 flex items-center justify-center rounded-lg hover:bg-gray-100 text-gray-400 hover:text-gray-600 transition-colors cursor-pointer"
                  >
                    <CheckCheck className="h-4 w-4" />
                  </button>
                )} */}
              </div>

              <div className="flex flex-col max-h-[60vh] sm:max-h-[420px] overflow-y-auto">
                {isLoading ? (
                  <div className="px-4 py-8 text-center text-sm text-gray-500 font-sans">
                    Loading…
                  </div>
                ) : notifications.length === 0 ? (
                  <div className="px-4 py-8 text-center text-sm text-gray-500 font-sans">
                    No notifications yet
                  </div>
                ) : (
                  notifications.map((item) => {
                    const styles = getStyle(item.notification?.code ?? "");
                    const question =
                      item.replacements?.title ||
                      item.replacements?.data?.title ||
                      "";
                    const answerHtml =
                      item.resolvedData?.answer ??
                      item.replacements?.data?.answer;
                    // Stripped text is used for the truthiness guard and the
                    // title tooltip (which can't hold markup); the raw HTML is
                    // rendered inline below.
                    const answer = stripHtml(answerHtml);

                    return (
                      <div
                        key={item.id}
                        onClick={() => handleNotificationClick(item)}
                        className={`flex flex-col relative cursor-pointer ${item.isRead ? "bg-white" : styles.wrapper}`}
                      >
                        <span
                          className={`absolute left-0 top-0 bottom-0 w-1 ${styles.accent}`}
                          aria-hidden
                        />
                        {!item.isRead && (
                          <span
                            className="absolute right-3 top-1 h-2 w-2 rounded-full bg-blue-500"
                            aria-hidden
                          />
                        )}
                        <div className="py-4 pr-4 pl-5 flex flex-col gap-1.5">
                          {question && (
                            <p
                              className="text-black text-sm font-semibold font-sans leading-5 truncate"
                              title={question}
                            >
                              {question}
                            </p>
                          )}
                          {answer && (
                            <div
                              className="text-gray-700 text-xs font-normal font-sans leading-4 line-clamp-2 [&_p]:m-0"
                              title={answer}
                            >
                              <span className="text-gray-500 font-medium">
                                Your answer:
                              </span>{" "}
                              <span
                                dangerouslySetInnerHTML={{ __html: answerHtml }}
                              />
                            </div>
                          )}
                          <div className="flex items-center gap-2 mt-1 flex-wrap">
                            <span
                              className={`inline-flex items-center px-2 py-0.5 rounded-full text-[10px] font-semibold uppercase tracking-wide font-sans ${styles.pill}`}
                            >
                              {styles.label}
                            </span>
                            <span className="text-neutral-500 text-xs font-medium font-sans leading-4">
                              {styles.verdict} ·{" "}
                              {moment(item.createdAt).fromNow()}
                            </span>
                          </div>
                        </div>
                        <div className="h-px bg-slate-200" />
                      </div>
                    );
                  })
                )}
              </div>
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}
