"use client";

import { useEffect, useId, useRef, useState, type RefObject } from "react";
import { useTheme } from "@/components/theme/ThemeProvider";
import {
  errorListCategories,
  filterErrorLists,
  groupErrorLists,
  shouldCloseOnBackdrop,
  trapFocusIndex,
} from "@/lib/errors/error-content-picker";
import type { Lang } from "@/lib/i18n";
import type { ErrorListItem } from "@/lib/types";
import styles from "./ErrorContentPicker.module.css";

interface ErrorContentPickerProps {
  items: readonly ErrorListItem[];
  lang: Lang;
  /** 今の値（下書き優先）。未選択は null */
  currentId: number | null;
  /** 閉じたときにフォーカスを戻すボタン */
  restoreFocusRef: RefObject<HTMLButtonElement | null>;
  onPick: (id: number) => void;
  onClose: () => void;
}

/** Tab の閉じ込めに使う、窓の中のフォーカスできる要素 */
const FOCUSABLE_SELECTOR = [
  "button:not([disabled])",
  "input:not([disabled])",
  "select:not([disabled])",
  "textarea:not([disabled])",
  "a[href]",
  '[tabindex]:not([tabindex="-1"])',
].join(", ");

/**
 * エラー一覧でエラー内容を選ぶ窓（この画面専用。指示書BE §4-1。D-185）。
 * 共通部品にはしない。分類名・詳細は `t()` に通さない。
 */
export function ErrorContentPicker({
  items,
  lang,
  currentId,
  restoreFocusRef,
  onPick,
  onClose,
}: ErrorContentPickerProps) {
  const { t } = useTheme();
  const titleId = useId();
  const keywordRef = useRef<HTMLInputElement>(null);
  const panelRef = useRef<HTMLDivElement>(null);
  /** mousedown が背景そのものに起きたか（窓の中で押して背景で離したときに閉じないため） */
  const downOnOverlayRef = useRef(false);
  const [keyword, setKeyword] = useState("");
  const [categoryKey, setCategoryKey] = useState<string | null>(null);

  useEffect(() => {
    keywordRef.current?.focus();
    const opener = restoreFocusRef.current;
    return () => {
      opener?.focus();
    };
  }, [restoreFocusRef]);

  useEffect(() => {
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === "Escape") {
        onClose();
        return;
      }
      if (e.key !== "Tab") return;
      const panel = panelRef.current;
      if (!panel) return;
      // 絞り込みで並びが変わるので、押すたびに数える
      const focusables = Array.from(panel.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));
      const active = document.activeElement;
      const activeIndex = active instanceof HTMLElement ? focusables.indexOf(active) : -1;
      const next = trapFocusIndex(focusables.length, activeIndex, e.shiftKey);
      if (focusables.length === 0) {
        e.preventDefault();
        return;
      }
      if (next !== null) {
        e.preventDefault();
        focusables[next]?.focus();
      }
    };
    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [onClose]);

  const categories = errorListCategories(items);
  const filtered = filterErrorLists(items, { lang, keyword, categoryKey });
  const groups = groupErrorLists(lang, filtered);
  const countLabel = t("{n}件 / {total}件")
    .replace("{n}", String(filtered.length))
    .replace("{total}", String(items.length));

  return (
    <div
      className={styles.overlay}
      onMouseDown={(e) => {
        downOnOverlayRef.current = e.target === e.currentTarget;
      }}
      onClick={(e) => {
        const downOnOverlay = downOnOverlayRef.current;
        downOnOverlayRef.current = false;
        if (shouldCloseOnBackdrop(downOnOverlay, e.target === e.currentTarget)) onClose();
      }}
    >
      <div
        ref={panelRef}
        className={styles.panel}
        role="dialog"
        aria-modal="true"
        aria-labelledby={titleId}
        onClick={(e) => e.stopPropagation()}
      >
        <div className={styles.header}>
          <h2 id={titleId} className={styles.title}>
            {t("エラー内容を選ぶ")}
          </h2>
          <button type="button" className={styles.close} onClick={onClose}>
            {t("閉じる")}
          </button>
        </div>
        <div className={styles.filters}>
          <select
            className={styles.category}
            aria-label={t("分類")}
            value={categoryKey ?? ""}
            onChange={(e) => setCategoryKey(e.target.value === "" ? null : e.target.value)}
          >
            <option value="">{t("すべての分類")}</option>
            {categories.map((category) => (
              <option key={category.key} value={category.key}>
                {lang === "ja" ? category.ja : category.en}
              </option>
            ))}
          </select>
          <input
            ref={keywordRef}
            className={styles.keyword}
            aria-label={t("キーワード")}
            value={keyword}
            onChange={(e) => setKeyword(e.target.value)}
          />
          <span className={styles.count}>{countLabel}</span>
          <button
            type="button"
            className={styles.clear}
            onClick={() => {
              setKeyword("");
              setCategoryKey(null);
            }}
          >
            {t("クリア")}
          </button>
        </div>
        <div className={styles.list}>
          {filtered.length === 0 ? (
            <div className={styles.empty}>{t("該当するエラー内容がありません")}</div>
          ) : (
            groups.map((group, index) => (
              <div key={`${group.heading}\u241e${index}`} className={styles.group}>
                <div className={styles.heading}>{group.heading}</div>
                {group.items.map((item) => {
                  const detail = lang === "ja" ? item.error_detail_ja : item.error_detail_en;
                  const current = item.id === currentId;
                  return (
                    <button
                      key={item.id}
                      type="button"
                      className={current ? `${styles.item} ${styles.itemCurrent}` : styles.item}
                      aria-current={current ? "true" : undefined}
                      title={detail}
                      onClick={() => onPick(item.id)}
                    >
                      <span className={styles.itemText}>{detail}</span>
                      {item.note_required && <span className={styles.chip}>{t("備考必須")}</span>}
                    </button>
                  );
                })}
              </div>
            ))
          )}
        </div>
      </div>
    </div>
  );
}
