"use client";

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

/**
 * 미리보기 — 토큰 이름으로 무엇을 보여줄지 고른다.
 *
 * ⚠️ 값은 그 토큰의 CSS 변수가 아니라 **그 섹션의 선언 원문**을 넣는다. `var(--fox-그토큰)`을
 * 쓰면 PC 섹션을 좁은 창에서 볼 때 모바일 값이 그려지고 Light 섹션이 다크 테마에서 다크 색으로
 * 그려진다 — 이 화면은 각 모드가 정의한 값을 보여야 하므로 현재 테마·뷰포트에 흔들리면 안 된다.
 * 원문이 참조(`var(--fox-primitive-…)`)인 경우는 그대로 넣어도 안전하다. 참조 대상인
 * primitive·theme는 모드와 무관한 단일 값이기 때문이다.
 * 인라인 `style`을 쓰는 예외인 이유도 같다: 렌더할 토큰을 미리 알 수 없다.
 */
const PREVIEWS: { match: RegExp; render: (value: string) => ReactNode }[] = [
  {
    match: /(^|-)padding(-|$)/,
    render: (value) => (
      <div className={styles.demoPadBox} style={{ padding: value }}>
        <p className={styles.demoText}>첫 번째 문단</p>
        <p className={styles.demoText}>두 번째 문단</p>
      </div>
    ),
  },
  {
    match: /(^|-)(gap|gutter)(-|$)|^spacing-/,
    render: (value) => (
      <div className={styles.demoGapBox} style={{ gap: value }}>
        <p className={styles.demoText}>첫 번째 문단</p>
        <p className={styles.demoText}>두 번째 문단</p>
      </div>
    ),
  },
  {
    match: /(^|-)radius(-|$)/,
    render: (value) => <div className={styles.demoRadius} style={{ borderRadius: value }} />,
  },
  {
    // 브라우저가 자체적으로 그리는 컨트롤이라 별도 에셋 없이 크기만 확인할 수 있다.
    match: /(^|-)icon(-|$)/,
    render: (value) => (
      <input
        type="checkbox"
        defaultChecked
        aria-label="크기 미리보기"
        className={styles.demoIcon}
        style={{ inlineSize: value, blockSize: value }}
      />
    ),
  },
  {
    match: /^border-/,
    render: (value) => <div className={styles.demoBorder} style={{ borderWidth: value }} />,
  },
  {
    match: /^shadow-/,
    render: (value) => (
      <div
        className={styles.demoShadow}
        style={{ boxShadow: `0 0 ${value} var(--demo-shadow-color)` }}
      />
    ),
  },
  {
    match: /^backdrop-/,
    render: (value) => (
      <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(${value})`, WebkitBackdropFilter: `blur(${value})` }}
        />
      </div>
    ),
  },
  {
    match: /^font-size-/,
    render: (value) => (
      <p className={styles.demoType} style={{ fontSize: value }}>
        다람쥐 헌 쳇바퀴에 타고파 · Handgloves 0123
      </p>
    ),
  },
  {
    match: /^font-family-/,
    render: (value) => (
      <p className={styles.demoType} style={{ fontFamily: value }}>
        다람쥐 헌 쳇바퀴에 타고파 · Handgloves 0123
      </p>
    ),
  },
  {
    match: /^font-weight-/,
    render: (value) => (
      <p className={styles.demoType} style={{ fontWeight: value }}>
        다람쥐 헌 쳇바퀴에 타고파 · Handgloves 0123
      </p>
    ),
  },
];

function previewFor(token: CssToken): ReactNode {
  if (isColor(token)) {
    // 색은 값 칸의 칩이 이미 보여준다.
    return null;
  }
  const hit = PREVIEWS.find((entry) => entry.match.test(token.name));
  return hit ? hit.render(token.declaration) : null;
}

/** 색 토큰 판별 — 이 세 접두사만 색이다(font-·number-는 아니다). */
function isColor(token: CssToken): boolean {
  return /^(color|primitive|theme)-/.test(token.name);
}

/**
 * 칩 배경으로 선언 원문을 그대로 넣는다. 참조(`var(--fox-primitive-neutral-0)`)든
 * 리터럴이든 CSS가 알아서 해석하고, 참조 대상인 primitive·theme는 모드와 무관한
 * 값이라 Light 섹션은 라이트 색이, Dark 섹션은 다크 색이 정확히 그려진다.
 */
function chipStyle(token: CssToken): CSSProperties {
  return { background: token.declaration };
}

export function TokenView({ section }: { section: CssSection }) {
  const hasPreview = section.tokens.some((token) => previewFor(token) !== null);
  const foreignCount = section.tokens.filter((token) => token.foreignAlias).length;

  return (
    <section className={styles.section}>
      <h2 className={styles.sectionTitle}>
        {section.label} · {section.tokens.length}
      </h2>
      <p className={styles.sectionNote}>
        {section.source} — 값은 매니페스트가 아니라 실제 스타일시트에서 읽습니다. 참조면
        가리키는 토큰을, 아니면 값을 표시합니다.
        {foreignCount > 0
          ? ` 이 중 ${foreignCount}개는 원본 Figma에서 제공되지 않은 컬렉션을 가리켜 값으로 굳어졌습니다.`
          : ""}
      </p>

      <table className={styles.table}>
        <thead>
          <tr>
            <th scope="col">토큰</th>
            <th scope="col">값 / 참조</th>
            {hasPreview ? <th scope="col">미리보기</th> : null}
          </tr>
        </thead>
        <tbody>
          {section.tokens.map((token) => (
            <tr key={token.name}>
              <td>
                <span className={styles.tokenName}>{token.name}</span>
                <span className={styles.tokenFigma}>{token.figma}</span>
              </td>
              <td className={styles.tdValue}>
                {isColor(token) ? (
                  <span className={styles.colorChip} style={chipStyle(token)} />
                ) : null}
                {token.alias !== null ? (
                  <span className={styles.aliasRef} title="참조 토큰">
                    → {token.alias}
                  </span>
                ) : (
                  token.declaration
                )}
                {token.foreignAlias ? (
                  <span
                    className={styles.aliasForeign}
                    title="원본 Figma에서는 참조였으나 해당 컬렉션이 제공되지 않아 값으로 굳어졌습니다"
                  >
                    {" "}
                    ({token.foreignAlias})
                  </span>
                ) : null}
              </td>
              {hasPreview ? <td className={styles.tdDemo}>{previewFor(token)}</td> : null}
            </tr>
          ))}
        </tbody>
      </table>
    </section>
  );
}
