import { useRef, useState } from "react";
import { useOutsideDismiss } from "../../shared/hooks/useOutsideDismiss.js";
import { useBackLayer } from "../../app/useBackLayer.js";
import { useI18n } from "../../shared/I18nProvider.jsx";
import { TrashIcon } from "../../shared/ActionIcons.jsx";
import { accountDisplayName } from "../accounts/account-display.js";
import { activeSessionTitle, otherActiveSessions } from "./active-sessions.js";
import { notificationSwipeAxis, notificationSwipeOffset, shouldDismissNotificationSwipe } from "./notification-swipe.js";

function DismissibleNotificationItem({ notification, completed, onOpen, onDismiss, children }) {
  const { t } = useI18n();
  const gestureRef = useRef(null);
  const suppressClickRef = useRef(false);
  const [offset, setOffset] = useState(0);
  const [dragging, setDragging] = useState(false);

  function handlePointerDown(event) {
    if (event.isPrimary === false || (event.pointerType === "mouse" && event.button !== 0)) return;
    suppressClickRef.current = false;
    gestureRef.current = {
      pointerId: event.pointerId,
      startX: event.clientX,
      startY: event.clientY,
      width: event.currentTarget.getBoundingClientRect().width,
      axis: null
    };
    event.currentTarget.setPointerCapture?.(event.pointerId);
  }

  function handlePointerMove(event) {
    const gesture = gestureRef.current;
    if (!gesture || gesture.pointerId !== event.pointerId) return;
    const deltaX = event.clientX - gesture.startX;
    const deltaY = event.clientY - gesture.startY;
    if (!gesture.axis) gesture.axis = notificationSwipeAxis(deltaX, deltaY);
    if (gesture.axis !== "horizontal") return;
    suppressClickRef.current = true;
    setDragging(true);
    setOffset(notificationSwipeOffset(deltaX, gesture.axis, gesture.width));
  }

  function releasePointer(event) {
    if (event.currentTarget.hasPointerCapture?.(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
  }

  function handlePointerEnd(event) {
    const gesture = gestureRef.current;
    if (!gesture || gesture.pointerId !== event.pointerId) return;
    const deltaX = event.clientX - gesture.startX;
    const deltaY = event.clientY - gesture.startY;
    const shouldDismiss = gesture.axis === "horizontal" && shouldDismissNotificationSwipe(deltaX, deltaY);
    gestureRef.current = null;
    releasePointer(event);
    setDragging(false);
    if (shouldDismiss) {
      onDismiss(notification.id);
      return;
    }
    setOffset(0);
  }

  function handlePointerCancel(event) {
    if (gestureRef.current?.pointerId !== event.pointerId) return;
    gestureRef.current = null;
    suppressClickRef.current = false;
    setDragging(false);
    setOffset(0);
  }

  function handleClick(event) {
    if (suppressClickRef.current) {
      suppressClickRef.current = false;
      event.preventDefault();
      return;
    }
    onOpen(notification);
  }

  return <div className={`notification-center-swipe${dragging ? " notification-center-swipe--dragging" : ""}`}>
    <span className="notification-center-dismiss-cue" aria-hidden="true"><TrashIcon className="notification-center-dismiss-icon" /></span>
    <button className={`${completed ? "notification-center-item notification-center-item--completed" : "notification-center-item"} notification-center-swipe-item`} style={{ "--notification-swipe-offset": `${offset}px` }} type="button" onPointerDown={handlePointerDown} onPointerMove={handlePointerMove} onPointerUp={handlePointerEnd} onPointerCancel={handlePointerCancel} onLostPointerCapture={handlePointerCancel} onClick={handleClick}>
      {children}
    </button>
    <button className="notification-center-dismiss-action" type="button" aria-label={t("notification.dismiss")} onClick={() => onDismiss(notification.id)}><TrashIcon className="notification-center-dismiss-icon" /></button>
  </div>;
}

export function NotificationCenter({ notifications, accounts = [], currentStatus, statusDisabled = false, sessions = [], currentSession, threads = [], notificationError, refreshErrors = [], onPopupOpen, onStatusOpen, onOpen, onDismiss, onActiveSessionOpen, onClear }) {
  const { language, t } = useI18n();
  const [open, setOpen] = useState(false);
  const otherNotifications = notifications.filter((notification) => notification.sessionId !== currentSession?.id);
  const hasAlert = otherNotifications.length > 0 || Boolean(notificationError) || refreshErrors.length > 0;
  const liveSessions = otherActiveSessions(sessions, currentSession);
  const hasContent = liveSessions.length > 0 || hasAlert;
  const otherChatAlertLabel = otherNotifications.length > 0
    ? t("notification.otherChatAlerts", { count: otherNotifications.length })
    : "";
  const centerRef = useRef(null);
  const closeCenter = useBackLayer(open, () => setOpen(false), "notifications");
  useOutsideDismiss(centerRef, closeCenter, open);

  function openNotification(notification) {
    closeCenter(() => onOpen(notification));
  }

  function openActiveSession(session) {
    closeCenter(() => onActiveSessionOpen(session));
  }

  function clearNotifications() {
    closeCenter(onClear);
  }

  function toggleNotificationCenter() {
    if (open) {
      closeCenter();
      return;
    }
    const openNotificationCenter = () => setOpen(true);
    if (onPopupOpen) onPopupOpen(openNotificationCenter);
    else openNotificationCenter();
  }

  function notificationTitle(notification) {
    const key = `notification.type.${notification.type}`;
    const translated = t(key);
    return translated === key ? notification.title : translated;
  }

  function notificationDetail(notification) {
    if (notification.detail === "Unknown project") return t("notification.unknownProject");
    const usage = /^(5h|Weekly) limit (\d+)% (remaining|available)$/.exec(notification.detail || "");
    const legacyUsage = /^(.*?)\s·\s(5h|Weekly|5시간|주간)\s(\d+)%/.exec(notification.detail || "");
    if (!usage && !legacyUsage) return notification.detail;
    const window = usage?.[1] ?? legacyUsage[2];
    const percent = usage?.[2] ?? legacyUsage[3];
    const windowLabel = language === "ko" ? (window === "5h" || window === "5시간" ? "5시간" : "주간") : window;
    return t("notification.limitRemaining", { window: windowLabel, percent });
  }

  function notificationAccount(notification) {
    const account = accounts.find((item) => item.id === notification.accountId);
    return account?.email ?? (account ? accountDisplayName(account, accounts) : "");
  }

  function activeSessionStatus(session) {
    const key = {
      sending: "conversation.sending",
      starting: "context.chat.starting",
      thinking: "activity.thinking",
      running: "context.chat.answering",
      waiting_approval: "context.chat.waitingApproval",
      waiting_response: "context.chat.waitingResponse"
    }[session.status];
    return key ? t(key) : t("context.chat.ready");
  }

  function sessionForNotification(notification) {
    if (currentSession?.id === notification.sessionId) return currentSession;
    return sessions.find((session) => session.id === notification.sessionId);
  }

  function refreshErrorMessage(error) {
    if (error.kind === "sessions") return t("notification.sessionsRefreshFailed");
    const account = accounts.find((item) => item.id === error.accountId);
    const name = account?.email ?? (account ? accountDisplayName(account, accounts) : "");
    return t("notification.usageRefreshFailed", { account: name || t("context.unavailable") });
  }

  return <div className="notification-center" ref={centerRef}>
    <button className="context-project-status" type="button" disabled={statusDisabled} onClick={onStatusOpen} aria-label={t("context.openLastChat")}>
      <span className="notification-center-current-status">{currentStatus}</span>{otherChatAlertLabel && <><span className="notification-center-trigger-separator" aria-hidden="true">/</span><span className="notification-center-trigger-label">{otherChatAlertLabel}</span></>}
    </button>
    <button className="notification-center-trigger" type="button" aria-label={t("notification.openNotifications")} aria-expanded={open} onClick={toggleNotificationCenter}>
      <i className={hasAlert ? "context-project-indicator context-project-indicator--notification" : liveSessions.length > 0 ? "context-project-indicator context-project-indicator--active" : "context-project-indicator context-project-indicator--complete"} aria-hidden="true" />
    </button>
    {open && <section className="notification-center-panel" aria-label={t("notification.title")}>
      <header><strong>{t("notification.title")}</strong><button type="button" onClick={clearNotifications}>{t("notification.clear")}</button></header>
      {notificationError && <p className="notification-center-error">{t("notification.openFailed")}</p>}
      {refreshErrors.map((error) => <p className="notification-center-error" key={`${error.kind}:${error.accountId ?? ""}`}>{refreshErrorMessage(error)}</p>)}
      <div className="notification-center-list">
        {!hasContent && <p className="notification-center-empty">{t("notification.empty")}</p>}
        {otherNotifications.length > 0 && <div className="notification-center-section">
          {otherNotifications.map((notification) => {
            const relatedSession = sessionForNotification(notification);
            const completed = notification.type === "completed";
            return <DismissibleNotificationItem notification={notification} completed={completed} key={notification.id} onOpen={openNotification} onDismiss={onDismiss}>
              {completed ? <><strong className="notification-title"><b>{relatedSession?.projectLabel || notification.detail || t("notification.unknownProject")}</b><small>{notificationTitle(notification)}</small></strong><span>{activeSessionTitle(relatedSession ?? {}, threads, t("notification.untitledChat"), notification.conversationTitle)}</span></> : <><strong className="notification-title"><b>{notificationTitle(notification)}</b>{notificationAccount(notification) && <small>{notificationAccount(notification)}</small>}</strong><span title={notificationDetail(notification)}>{notificationDetail(notification)}</span></>}
            </DismissibleNotificationItem>;
          })}
        </div>}
        {liveSessions.length > 0 && <section className="notification-center-section"><h2 className="notification-center-section-title">{t("notification.activeTitle")}</h2>
          {liveSessions.map((session) => <button className="notification-center-item notification-center-item--active" type="button" key={session.id} onClick={() => openActiveSession(session)}>
            <strong className="notification-title"><b>{session.projectLabel || t("notification.unknownProject")}</b><small>{activeSessionStatus(session)}</small></strong>
            <span>{activeSessionTitle(session, threads, t("notification.untitledChat"))}</span>
          </button>)}
        </section>}
      </div>
    </section>}
  </div>;
}
