"use client";

import type { CSSProperties, ReactNode } from "react";
import type { TokenEntry } from "./read-tokens";
import styles from "./dev-test.module.scss";

/**
 * 토큰 **목록**은 CSSOM에서 읽으므로 여기에 적지 않는다. 이 표는 각 그룹을 어떻게
 * 보여줄지와 한글 이름만 정한다. 목록에 없는 그룹이 새로 생겨도 값 표로 그려진다.
 *
 * - `swatch` 색을 칠한 카드
 * - `type`   그 서체 속성을 실제로 적용한 문장
 * - `demo`   그 토큰을 실제로 적용한 요소 (그룹별 렌더는 `DEMOS`)
 * - `value`  값만
 */
export const TOKEN_GROUPS: {
  key: string;
  label: string;
  kind: "swatch" | "type" | "demo" | "value";
  note?: string;
}[] = [
  {
    key: "color",
    label: "시맨틱 색상",
    kind: "swatch",
    note: "light/dark 값이 light-dark() 한 줄에 함께 정의돼 있습니다. 좌측 전환기로 두 테마를 대조해 보세요.",
  },
  { key: "theme", label: "브랜드 램프", kind: "swatch", note: "primary · secondary · accent" },
  {
    key: "primitive",
    label: "원시 팔레트",
    kind: "swatch",
    note: "화면에서 직접 쓰지 않는 바닥층입니다. 시맨틱 색상이 이 값들을 참조합니다.",
  },
  {
    key: "font",
    label: "서체",
    kind: "type",
    note: "각 토큰을 실제로 적용한 문장입니다. size 계열은 768px 경계에서 값이 바뀝니다.",
  },
  {
    key: "padding",
    label: "패딩",
    kind: "demo",
    note: "테두리와 문단 사이의 여백이 토큰 값입니다.",
  },
  { key: "gap", label: "간격", kind: "demo", note: "두 문단 사이의 거리가 토큰 값입니다." },
  { key: "radius", label: "모서리 반경", kind: "demo" },
  {
    key: "icon",
    label: "아이콘 크기",
    kind: "demo",
    note: "브라우저가 그리는 기본 체크박스를 토큰 크기로 키운 것입니다.",
  },
  { key: "border", label: "테두리 두께", kind: "demo", note: "border-0은 값이 0이라 보이지 않습니다." },
  { key: "number", label: "원시 수치", kind: "value" },
  {
    key: "shadow",
    label: "그림자 수치",
    kind: "demo",
    note: "Figma에는 offset·blur 수치만 있고 완성된 그림자 토큰이 없습니다. 각 수치의 효과를 보이려고 location은 `0 값 0`, blur는 `0 0 값`으로 조합했고 색은 alpha-default-inverse25를 씁니다 — 조합 자체는 토큰이 아닙니다.",
  },
  {
    key: "backdrop",
    label: "배경 흐림",
    kind: "demo",
    note: "오른쪽 절반에만 backdrop-filter를 걸어 원본과 대조합니다.",
  },
  { key: "form", label: "폼", kind: "value" },
  { key: "card", label: "카드", kind: "value" },
  { key: "modal", label: "모달", kind: "value" },
  { key: "grid", label: "그리드", kind: "value" },
  { key: "spacing", label: "여백", kind: "value" },
  { key: "section", label: "섹션", kind: "value" },
];

/**
 * ⚠️ 인라인 `style`을 쓰는 **유일하게 허용되는 예외**다. 개수를 미리 알 수 없는 토큰을
 * 런타임에 순회해야 하는데, CSS 클래스는 알 수 없는 이름에 대해 만들 수 없다. 여기서
 * 넣는 값은 디자인 값이 아니라 **토큰 참조**(`var(--fox-*)`)이며 실제 값은 여전히
 * 토큰이 소유한다. 일반 컴포넌트에서는 이 패턴을 쓰지 않는다.
 */
function v(token: TokenEntry): string {
  return `var(${token.property})`;
}

/**
 * 화면에 표시할 토큰 식별자. `--fox-` 접두사만 뗀 **실제 이름**이라 CSS 변수
 * (`--fox-color-background-default`)와 그대로 대응한다 — 함수 표기(`fox.color(...)`)는
 * 그룹명이 괄호 밖으로 빠져 목록을 훑을 때 이름이 한눈에 안 들어온다.
 */
function label(token: TokenEntry): string {
  return token.property.replace("--fox-", "");
}

// ── 그룹별 미리보기 ─────────────────────────────────────────────────────────
const DEMOS: Record<string, (token: TokenEntry) => ReactNode> = {
  padding: (token) => (
    <div className={styles.demoPadBox} style={{ padding: v(token) }}>
      <p className={styles.demoText}>첫 번째 문단</p>
      <p className={styles.demoText}>두 번째 문단</p>
    </div>
  ),

  gap: (token) => (
    <div className={styles.demoGapBox} style={{ gap: v(token) }}>
      <p className={styles.demoText}>첫 번째 문단</p>
      <p className={styles.demoText}>두 번째 문단</p>
    </div>
  ),

  radius: (token) => <div className={styles.demoRadius} style={{ borderRadius: v(token) }} />,

  // 브라우저가 자체적으로 그리는 컨트롤이라 별도 에셋 없이 크기만 확인할 수 있다.
  icon: (token) => (
    <input
      type="checkbox"
      defaultChecked
      aria-label={`icon-${token.name} 크기 미리보기`}
      className={styles.demoIcon}
      style={{ inlineSize: v(token), blockSize: v(token) }}
    />
  ),

  border: (token) => <div className={styles.demoBorder} style={{ borderWidth: v(token) }} />,

  shadow: (token) => (
    <div
      className={styles.demoShadow}
      style={{
        boxShadow: token.name.startsWith("blur")
          ? `0 0 ${v(token)} var(--demo-shadow-color)`
          : `0 ${v(token)} 0 var(--demo-shadow-color)`,
      }}
    />
  ),

  backdrop: (token) => (
    <div className={styles.demoBackdrop}>
      {/* eslint-disable-next-line @next/next/no-img-element -- @fox는 프레임워크에 의존하지
          않아야 이식된다. next/image를 쓰면 이 폴더가 Next 전용이 되고 외부 호스트마다
          remotePatterns 설정도 필요해진다. */}
      <img
        src="https://picsum.photos/seed/picsum/200/300"
        alt=""
        className={styles.demoBackdropImage}
      />
      <div
        className={styles.demoBackdropOverlay}
        style={{
          backdropFilter: `blur(${v(token)})`,
          WebkitBackdropFilter: `blur(${v(token)})`,
        }}
      />
    </div>
  ),
};

// ── 렌더러 ──────────────────────────────────────────────────────────────────
function Swatches({ tokens }: { tokens: TokenEntry[] }) {
  return (
    <div className={styles.swatchGrid}>
      {tokens.map((token) => (
        <div key={token.property} className={styles.swatch}>
          <div className={styles.swatchChip} style={{ background: v(token) }} />
          <div className={styles.swatchMeta}>
            <span className={styles.tokenName}>{label(token)}</span>
            <span className={styles.tokenValue}>{token.value}</span>
          </div>
        </div>
      ))}
    </div>
  );
}

/** 서체 토큰은 이름 앞머리가 곧 적용할 CSS 속성이다. */
function typeStyle(token: TokenEntry): CSSProperties {
  if (token.name.startsWith("family-")) {
    return { fontFamily: v(token) };
  }
  if (token.name.startsWith("weight-")) {
    return { fontWeight: v(token) };
  }
  return { fontSize: v(token) };
}

function TypeList({ tokens }: { tokens: TokenEntry[] }) {
  return (
    <div className={styles.typeList}>
      {tokens.map((token) => (
        <div key={token.property} className={styles.typeRow}>
          <div className={styles.typeMeta}>
            <span className={styles.tokenName}>{label(token)}</span>
            <span className={styles.tokenValue}>{token.value}</span>
          </div>
          <p className={styles.typeSample} style={typeStyle(token)}>
            다람쥐 헌 쳇바퀴에 타고파 · Handgloves 0123
          </p>
        </div>
      ))}
    </div>
  );
}

function TokenTable({
  tokens,
  demo,
}: {
  tokens: TokenEntry[];
  demo?: (token: TokenEntry) => ReactNode;
}) {
  return (
    <table className={styles.table}>
      <thead>
        <tr>
          <th scope="col">토큰</th>
          <th scope="col">값</th>
          {demo ? <th scope="col">미리보기</th> : null}
        </tr>
      </thead>
      <tbody>
        {tokens.map((token) => (
          <tr key={token.property}>
            <td>{label(token)}</td>
            <td className={styles.tdValue}>{token.value}</td>
            {demo ? <td className={styles.tdDemo}>{demo(token)}</td> : null}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

export function TokenView({ group, tokens }: { group: string; tokens: TokenEntry[] }) {
  const meta = TOKEN_GROUPS.find((entry) => entry.key === group);
  const kind = meta?.kind ?? "value";

  return (
    <section className={styles.section}>
      <h2 className={styles.sectionTitle}>
        {meta?.label ?? group} · {tokens.length}
      </h2>
      {meta?.note ? <p className={styles.sectionNote}>{meta.note}</p> : null}

      {kind === "swatch" ? <Swatches tokens={tokens} /> : null}
      {kind === "type" ? <TypeList tokens={tokens} /> : null}
      {kind === "demo" ? <TokenTable tokens={tokens} demo={DEMOS[group]} /> : null}
      {kind === "value" ? <TokenTable tokens={tokens} /> : null}
    </section>
  );
}
