"use client";

import { useSyncExternalStore } from "react";
import { cx } from "../core/utils";
import { COMPONENT_EXAMPLES } from "./component-registry";
import { ComponentEmpty, ComponentView } from "./component-view";
import { ThemeSwitch } from "./theme-switch";
import { TOKEN_GROUPS, TokenView } from "./token-view";
import { useTokenRegistry } from "./use-token-registry";
import styles from "./dev-test.module.scss";

// 선택 상태는 URL 해시가 SSOT다 — 새로고침하거나 링크를 공유해도 보던 섹션이 유지되고,
// React state를 따로 두지 않으므로 둘이 어긋날 일이 없다.
// 형식: `#token:color` / `#component:button`
function subscribeHash(onChange: () => void): () => void {
  window.addEventListener("hashchange", onChange);
  return () => window.removeEventListener("hashchange", onChange);
}

function getHash(): string {
  return window.location.hash.slice(1);
}

function getServerHash(): string {
  return "";
}

function useSelection(): { kind: string; id: string } | null {
  const hash = useSyncExternalStore(subscribeHash, getHash, getServerHash);
  const [kind, id] = hash.split(":");
  return kind && id ? { kind, id } : null;
}

function select(kind: string, id: string): void {
  window.location.hash = `${kind}:${id}`;
}

/** 안내 항목의 식별자 — 등록된 컴포넌트 id와 겹치지 않게 별도로 둔다. */
const GUIDE_ID = "guide";

function isRegistered(id: string): boolean {
  return COMPONENT_EXAMPLES.some((example) => example.id === id);
}

export function DevTestPage() {
  const registry = useTokenRegistry();
  const selection = useSelection();

  if (!registry) {
    return (
      <div className={styles.shell}>
        <p className={styles.loading}>토큰을 읽는 중…</p>
      </div>
    );
  }

  // 사이드바에 뜰 토큰 그룹 — 정의된 순서를 우선하고, 목록에 없는 그룹은 뒤에 붙인다.
  const known = TOKEN_GROUPS.filter((group) => registry[group.key]?.length);
  const extra = Object.keys(registry)
    .filter((key) => !TOKEN_GROUPS.some((group) => group.key === key))
    .map((key) => ({ key, label: key }));
  const tokenGroups = [...known, ...extra];

  const current = selection ?? { kind: "token", id: tokenGroups[0]?.key ?? "" };
  const totalTokens = Object.values(registry).reduce((sum, list) => sum + list.length, 0);

  return (
    <div className={styles.shell}>
      <aside className={styles.sidebar}>
        <div className={styles.brand}>
          <span className={styles.brandTitle}>@fox 디자인 시스템</span>
          <span className={styles.brandNote}>개발 전용 테스트 페이지</span>
        </div>

        <ThemeSwitch />

        <nav className={styles.nav} aria-label="섹션">
          <div className={styles.navGroup}>
            <h2 className={styles.navGroupTitle}>토큰 · {totalTokens}</h2>
            <ul className={styles.navList}>
              {tokenGroups.map((group) => (
                <li key={group.key}>
                  <button
                    type="button"
                    className={styles.navItem}
                    aria-current={
                      current.kind === "token" && current.id === group.key ? "page" : undefined
                    }
                    onClick={() => select("token", group.key)}
                  >
                    <span>{group.label}</span>
                    <span className={styles.navCount}>{registry[group.key].length}</span>
                  </button>
                </li>
              ))}
            </ul>
          </div>

          <div className={styles.navGroup}>
            <h2 className={styles.navGroupTitle}>컴포넌트 · {COMPONENT_EXAMPLES.length}</h2>
            <ul className={styles.navList}>
              {COMPONENT_EXAMPLES.map((example) => (
                <li key={example.id}>
                  <button
                    type="button"
                    className={styles.navItem}
                    aria-current={
                      current.kind === "component" && current.id === example.id
                        ? "page"
                        : undefined
                    }
                    onClick={() => select("component", example.id)}
                  >
                    <span>{example.name}</span>
                    <span className={styles.navCount}>{example.variants.length}</span>
                  </button>
                </li>
              ))}

              {/* 컴포넌트가 아니라 안내 항목이라 항상 목록 맨 아래에 두고 생김새를 달리한다.
                  등록된 컴포넌트가 없을 때도 사라지지 않아야 추가 방법을 찾을 수 있다. */}
              <li>
                <button
                  type="button"
                  className={cx(styles.navItem, styles.navItemGuide)}
                  aria-current={
                    current.kind === "component" && !isRegistered(current.id) ? "page" : undefined
                  }
                  onClick={() => select("component", GUIDE_ID)}
                >
                  <span>추가 방법</span>
                  <span aria-hidden="true" className={styles.navGuideMark}>
                    +
                  </span>
                </button>
              </li>
            </ul>
          </div>
        </nav>
      </aside>

      <main className={styles.content}>
        {current.kind === "component" ? (
          (() => {
            const example = COMPONENT_EXAMPLES.find((entry) => entry.id === current.id);
            return example ? <ComponentView example={example} /> : <ComponentEmpty />;
          })()
        ) : registry[current.id]?.length ? (
          <TokenView group={current.id} tokens={registry[current.id]} />
        ) : (
          <p className={styles.loading}>선택한 토큰 그룹이 없습니다.</p>
        )}
      </main>
    </div>
  );
}
