"use client";

import { useEffect, useRef, useState } from "react";
import { CloseIconButton } from "@/components/close-icon-button";
import type { KavenixAdminUserAuthActivity } from "@/lib/kavenix-admin";

type KavenixUserAuthActivityDialogProps = {
  companyName: string;
  displayName: string;
  loginEmail: string;
  recoveryEmail: string | null;
  userId: number;
};

type ActivityResponse = {
  activities?: KavenixAdminUserAuthActivity[];
  message?: string;
  nextCursor?: string | null;
  ok?: boolean;
};

function formatActivityTime(value: string) {
  const date = new Date(value);

  if (Number.isNaN(date.getTime())) {
    return "-";
  }

  return new Intl.DateTimeFormat("ko-KR", {
    day: "numeric",
    hour: "2-digit",
    hour12: true,
    minute: "2-digit",
    month: "long",
    second: "2-digit",
    timeZone: "Asia/Seoul",
    year: "numeric",
  }).format(date);
}

function eventLabel(eventType: KavenixAdminUserAuthActivity["eventType"]) {
  return eventType === "find_id" ? "아이디 찾기" : "로그인";
}

function outcomeMeta(outcome: string) {
  switch (outcome) {
    case "success":
      return { label: "성공", tone: "bg-[#eff9f3] text-[#28754b]" };
    case "invalid_credentials":
      return { label: "인증 실패", tone: "bg-[#fff3f5] text-[#ad3f56]" };
    case "rate_limited":
      return { label: "요청 제한", tone: "bg-[#fff8eb] text-[#9a651b]" };
    case "plan_restricted":
      return { label: "플랜 제한", tone: "bg-[#fff8eb] text-[#9a651b]" };
    case "not_found":
      return { label: "계정 없음", tone: "bg-[#f3f5f8] text-[#65738a]" };
    case "invalid_email":
      return { label: "형식 오류", tone: "bg-[#f3f5f8] text-[#65738a]" };
    default:
      return { label: "처리 오류", tone: "bg-[#fff3f5] text-[#ad3f56]" };
  }
}

function deviceLabel(userAgent: string | null, source: "app" | "web") {
  if (!userAgent) {
    return source === "app" ? "오피셜메일 앱" : "웹 브라우저";
  }

  const platform = /Android/i.test(userAgent)
    ? "Android"
    : /iPhone|iPad|iOS/i.test(userAgent)
      ? "iOS"
      : /Windows/i.test(userAgent)
        ? "Windows"
        : /Macintosh|Mac OS/i.test(userAgent)
          ? "macOS"
          : /Linux/i.test(userAgent)
            ? "Linux"
            : source === "app"
              ? "앱"
              : "기타";
  const browser = /Edg\//i.test(userAgent)
    ? "Edge"
    : /Chrome\//i.test(userAgent)
      ? "Chrome"
      : /Firefox\//i.test(userAgent)
        ? "Firefox"
        : /Safari\//i.test(userAgent) && !/Chrome\//i.test(userAgent)
          ? "Safari"
          : source === "app"
            ? "오피셜메일 앱"
            : "웹 브라우저";

  return `${platform} · ${browser}`;
}

export function KavenixUserAuthActivityDialog(
  props: KavenixUserAuthActivityDialogProps,
) {
  const [open, setOpen] = useState(false);

  return (
    <>
      <button
        type="button"
        onClick={() => setOpen(true)}
        className="mt-2 inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-[7px] border border-[#dce5f3] bg-white px-2.5 text-[11px] font-semibold text-[#536784] transition-colors hover:border-[#bfd0ee] hover:bg-[#f7faff] hover:text-[#2f6df6]"
      >
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="1.8"
          strokeLinecap="round"
          strokeLinejoin="round"
          className="h-3.5 w-3.5"
          aria-hidden="true"
        >
          <circle cx="12" cy="8" r="3.2" />
          <path d="M6.5 18.2a5.8 5.8 0 0 1 11 0" />
        </svg>
        정보 보기
      </button>
      {open ? (
        <UserAuthActivityPanel
          key={props.userId}
          {...props}
          onClose={() => setOpen(false)}
        />
      ) : null}
    </>
  );
}

function UserAuthActivityPanel({
  companyName,
  displayName,
  loginEmail,
  recoveryEmail,
  userId,
  onClose,
}: KavenixUserAuthActivityDialogProps & { onClose: () => void }) {
  const [activities, setActivities] = useState<KavenixAdminUserAuthActivity[]>(
    [],
  );
  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [cursor, setCursor] = useState<string | null>(null);
  const [nextCursor, setNextCursor] = useState<string | null>(null);
  const [retryAttempt, setRetryAttempt] = useState(0);
  const scrollRootRef = useRef<HTMLDivElement>(null);
  const sentinelRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const previousOverflow = document.body.style.overflow;

    function handleKeyDown(event: KeyboardEvent) {
      if (event.key === "Escape") {
        onClose();
      }
    }

    document.body.style.overflow = "hidden";
    window.addEventListener("keydown", handleKeyDown);

    return () => {
      document.body.style.overflow = previousOverflow;
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [onClose]);

  useEffect(() => {
    const controller = new AbortController();

    async function loadPage() {
      try {
        const query = cursor ? `?${new URLSearchParams({ cursor })}` : "";
        const response = await fetch(
          `/api/kavenix/users/${userId}/auth-activity${query}`,
          {
            cache: "no-store",
            credentials: "same-origin",
            signal: controller.signal,
          },
        );
        const payload = (await response
          .json()
          .catch(() => null)) as ActivityResponse | null;

        if (
          !response.ok ||
          !payload?.ok ||
          !Array.isArray(payload.activities) ||
          (payload.nextCursor !== null &&
            typeof payload.nextCursor !== "string") ||
          (payload.nextCursor !== null &&
            (payload.nextCursor === cursor || payload.activities.length === 0))
        ) {
          throw new Error(
            payload?.message || "접속 기록을 불러오지 못했습니다.",
          );
        }

        if (controller.signal.aborted) return;
        const page = payload.activities;
        setActivities((previous) => {
          if (!cursor) return page;
          const existingIds = new Set(previous.map((activity) => activity.id));
          return [
            ...previous,
            ...page.filter((activity) => !existingIds.has(activity.id)),
          ];
        });
        setNextCursor(payload.nextCursor);
      } catch (error) {
        if (controller.signal.aborted) return;
        setErrorMessage(
          error instanceof Error
            ? error.message
            : "접속 기록을 불러오지 못했습니다.",
        );
      } finally {
        if (!controller.signal.aborted) setLoading(false);
      }
    }

    void loadPage();
    return () => controller.abort();
  }, [userId, cursor, retryAttempt]);

  useEffect(() => {
    const root = scrollRootRef.current;
    const sentinel = sentinelRef.current;
    if (loading || errorMessage || !nextCursor || !root || !sentinel) return;

    let requested = false;
    const observer = new IntersectionObserver(
      (entries) => {
        if (requested || !entries.some((entry) => entry.isIntersecting)) return;
        requested = true;
        observer.disconnect();
        setLoading(true);
        setCursor(nextCursor);
      },
      { root, rootMargin: "0px 0px 200px 0px" },
    );
    observer.observe(sentinel);
    return () => {
      requested = true;
      observer.disconnect();
    };
  }, [loading, errorMessage, nextCursor]);

  return (
    <div
      className="fixed inset-0 z-[200] flex items-center justify-center bg-[rgba(12,18,31,0.44)] px-4 py-8"
      onClick={onClose}
    >
      <div
        role="dialog"
        ref={scrollRootRef}
        tabIndex={-1}
        aria-modal="true"
        aria-label={`${companyName || displayName || loginEmail} 접속 정보`}
        className="max-h-[calc(100vh-4rem)] w-full max-w-[760px] overflow-y-auto rounded-[18px] border border-[#dfe8f7] bg-white shadow-[0_28px_80px_rgba(15,23,42,0.22)]"
        onClick={(event) => event.stopPropagation()}
      >
        <div className="flex items-start justify-between gap-4 border-b border-[#edf2f8] px-5 py-5 sm:px-6">
          <div className="min-w-0">
            <p className="text-[20px] font-semibold tracking-[-0.04em] text-[#16233c]">
              사용자 접속 정보
            </p>
            <p className="mt-1 break-all text-[13px] text-[#667994]">
              {companyName || displayName || loginEmail} · {loginEmail}
            </p>
          </div>
          <CloseIconButton
            ariaLabel="사용자 접속 정보 닫기"
            onClick={onClose}
          />
        </div>

        <div className="grid border-b border-[#edf2f8] bg-[#f8faff] sm:grid-cols-2">
          <div className="px-5 py-4 sm:px-6">
            <p className="text-[11px] font-semibold text-[#8795aa]">
              로그인 계정
            </p>
            <p className="mt-1 break-all text-[13px] font-medium text-[#2c3e5b]">
              {loginEmail}
            </p>
          </div>
          <div className="border-t border-[#e9eef7] px-5 py-4 sm:border-l sm:border-t-0 sm:px-6">
            <p className="text-[11px] font-semibold text-[#8795aa]">
              보조 이메일
            </p>
            <p className="mt-1 break-all text-[13px] font-medium text-[#2c3e5b]">
              {recoveryEmail ?? "등록되지 않음"}
            </p>
          </div>
        </div>

        <div className="px-5 py-5 sm:px-6">
          <div className="flex items-end justify-between gap-3">
            <div>
              <p className="text-[14px] font-semibold text-[#263957]">
                최근 인증 활동
              </p>
              <p className="mt-1 text-[12px] leading-5 text-[#7a8ba7]">
                로그인과 아이디 찾기 요청을 최신순으로 표시합니다. 아래로
                스크롤하면 이전 기록을 불러옵니다.
              </p>
            </div>
            {activities.length > 0 ? (
              <span className="shrink-0 text-[12px] font-semibold text-[#2f6df6]">
                {activities.length}건 불러옴
              </span>
            ) : null}
          </div>

          {loading && activities.length === 0 ? (
            <div className="flex min-h-40 items-center justify-center text-[13px] text-[#73839f]">
              접속 기록을 불러오는 중입니다.
            </div>
          ) : !errorMessage && activities.length === 0 ? (
            <div className="mt-4 border border-[#e5ebf4] bg-[#fafcff] px-4 py-8 text-center text-[13px] leading-6 text-[#73839f]">
              기록 기능 적용 이후의 로그인과 아이디 찾기 요청이 여기에
              표시됩니다.
            </div>
          ) : activities.length > 0 ? (
            <div className="mt-4 divide-y divide-[#edf1f6] border-y border-[#e5ebf4]">
              {activities.map((activity) => {
                const outcome = outcomeMeta(activity.outcome);

                return (
                  <article
                    key={activity.id}
                    className="py-4 first:pt-3 last:pb-3"
                  >
                    <div className="flex flex-wrap items-center justify-between gap-2">
                      <div className="flex flex-wrap items-center gap-2">
                        <p className="text-[14px] font-semibold text-[#263957]">
                          {eventLabel(activity.eventType)}
                        </p>
                        <span
                          className={`rounded-full px-2 py-1 text-[10px] font-semibold ${outcome.tone}`}
                        >
                          {outcome.label}
                        </span>
                        <span className="rounded-full bg-[#f0f4fa] px-2 py-1 text-[10px] font-semibold text-[#62738e]">
                          {activity.source === "app" ? "앱" : "웹"}
                        </span>
                      </div>
                      <time className="text-[11px] text-[#7b8ca8]">
                        {formatActivityTime(activity.occurredAt)}
                      </time>
                    </div>
                    <div className="mt-3 grid gap-x-6 gap-y-2 text-[12px] sm:grid-cols-2">
                      <p className="text-[#71819c]">
                        IP{" "}
                        <span className="ml-1 font-medium text-[#344867]">
                          {activity.ipAddress ?? "확인 불가"}
                        </span>
                      </p>
                      <p className="text-[#71819c]">
                        환경{" "}
                        <span className="ml-1 font-medium text-[#344867]">
                          {deviceLabel(activity.userAgent, activity.source)}
                        </span>
                      </p>
                      <p className="break-all text-[#71819c] sm:col-span-2">
                        요청 계정{" "}
                        <span className="ml-1 font-medium text-[#344867]">
                          {activity.identityEmail}
                        </span>
                      </p>
                      {activity.userAgent ? (
                        <p
                          className="break-all text-[10px] leading-4 text-[#9aa6b8] sm:col-span-2"
                          title={activity.userAgent}
                        >
                          {activity.userAgent}
                        </p>
                      ) : null}
                    </div>
                  </article>
                );
              })}
            </div>
          ) : null}

          <div ref={sentinelRef} className="h-px" aria-hidden="true" />
          {errorMessage ? (
            <div
              role="alert"
              className="mt-4 flex flex-wrap items-center justify-between gap-3 text-[13px] text-[#a9475c]"
            >
              <p>{errorMessage}</p>
              <button
                type="button"
                className="cursor-pointer py-2 font-semibold text-[#2f6df6] hover:underline"
                onClick={() => {
                  setErrorMessage(null);
                  setLoading(true);
                  setRetryAttempt((attempt) => attempt + 1);
                }}
              >
                다시 불러오기
              </button>
            </div>
          ) : activities.length > 0 ? (
            <p
              role="status"
              className="pt-4 text-center text-[12px] text-[#7a8ba7]"
            >
              {loading
                ? "이전 접속 기록을 불러오는 중입니다."
                : nextCursor
                  ? "아래로 스크롤하면 이전 기록을 불러옵니다."
                  : "모든 접속 기록을 불러왔습니다."}
            </p>
          ) : null}
        </div>
      </div>
    </div>
  );
}
