#!/usr/bin/env bash
# Design-system lint (v2: paper-and-ink). Fails (exit 1) on drift.
# Wired into `bun run check`.
set -e
cd "$(dirname "$0")/.."

red()    { printf "\033[31m%s\033[0m\n" "$*"; }
green()  { printf "\033[32m%s\033[0m\n" "$*"; }
yellow() { printf "\033[33m%s\033[0m\n" "$*"; }

fail=0
total=0

check() {
  local label="$1"
  local pattern="$2"
  local exclude="$3"
  local hint="$4"
  total=$((total + 1))
  printf "  %-44s " "$label"
  local hits
  local skip_template='/_[A-Z]'
  if [ -n "$exclude" ]; then
    hits=$(grep -rEn "$pattern" src --include="*.tsx" --include="*.ts" 2>/dev/null | grep -vE "$exclude|$skip_template" || true)
  else
    hits=$(grep -rEn "$pattern" src --include="*.tsx" --include="*.ts" 2>/dev/null | grep -vE "$skip_template" || true)
  fi
  if [ -z "$hits" ]; then
    green "OK"
  else
    red "FAIL"
    echo "$hits" | sed 's/^/    /'
    if [ -n "$hint" ]; then
      yellow "    → Fix: $hint"
    fi
    fail=$((fail + 1))
  fi
}

echo
yellow "Design-system check (v2 paper-and-ink)"
echo

# 1. No arbitrary text-[Npx] / text-[Nrem]
check "type tokens (no text-[Npx])" \
  'text-\[[0-9]+(\.[0-9]+)?(px|rem|em)\]' \
  "" \
  "use semantic class .text-body / .text-small / .text-eyebrow / .text-mono — see ANTI-PATTERNS.md §Typography"

# 2. No arbitrary spacing/sizing.
check "spacing tokens (no [Npx]/[Nrem]/[Nem])" \
  '\b(p|px|py|pt|pb|pl|pr|m|mx|my|mt|mb|ml|mr|gap|space-[xy]|min-[wh]|max-[wh]|w|h)-\[[0-9]+(\.[0-9]+)?(px|rem|em)\]' \
  "" \
  "use spacing scale (gap-2, p-3, h-row). For new fixed dimensions, declare a class in src/index.css."

# 2b. No arbitrary durations
check "motion tokens (no duration-[Nms])" \
  'duration-\[[0-9]+(\.[0-9]+)?m?s\]' \
  "" \
  "use .transition-default. For other timings, declare a motion preset in src/index.css"

# 2c. No arbitrary transition property lists
check "motion tokens (no transition-[props])" \
  'transition-\[[^]]+\]' \
  "" \
  "use .transition-default."

# 2d. No Tailwind default shadow scales
check "shadow tokens (no shadow-{sm,inner,none})" \
  '\bshadow-(sm|inner|none|2xl)\b' \
  "" \
  "use .shadow-1 / .shadow-2 / .shadow-3 from src/index.css"

# 3. Off-grid n.5
check "spacing grid (no n.5 except 0.5 and 1.5)" \
  '\b(p|px|py|pt|pb|pl|pr|m|mx|my|mt|mb|ml|mr|gap|space-[xy])-([2-9]\.5|[0-9]{2,}\.5|[0-9]+\.[0-46-9])\b' \
  "" \
  "stay on the 4px grid. Only -0.5 (2px) and -1.5 (6px) sub-grid steps allowed for icon alignment"

# 4. No ad-hoc alpha-bg with brand colors
check "color tokens (no bg-X/N alpha drift)" \
  'bg-(white|black|accent|mint|warn|danger|ok)/(\[|[0-9])' \
  "" \
  "use the matching solid token (bg-mint-100, bg-paper-2, etc.). See docs/tokens.md"

# 5. No removed v1 dark-theme tokens
check "no v1 dark-theme tokens" \
  '\b(bg|text|border|ring)-(surface-(canvas|raised|hover|active|elevated)|fg-(default|muted|subtle|placeholder|disabled|on-accent|on-success|on-warn|on-danger)|border-(default|subtle|strong)|accent-(hover|soft)|success(-(hover|soft))?|warn-(hover|soft)|danger-(hover|soft)|chat|files|tint-chat|scrim)\b' \
  "" \
  "v1 tokens removed. Run: node scripts/migrate-tokens.mjs --apply  (then re-run check)"

# 5b. No removed v1 type-scale class names
# .text-display still exists in v2 (now 56px hero); the others were removed.
check "no v1 type-scale class names" \
  '\b(text-hero|text-heading|text-subheading|text-label|text-caption)\b' \
  "" \
  "renamed: text-hero→text-h1 (or text-display for 56px hero), text-heading→text-h4, text-subheading→text-body-lg, text-label→text-eyebrow, text-caption→text-mono"

# 6. No raw hex / rgb / rgba in components
check "no raw hex/rgb in components" \
  '(#[0-9a-fA-F]{3,8}\b|\brgba?\s*\()' \
  '\.(test|spec|stories)\.|//.*color|/\*.*color' \
  "all hex/rgb values live in src/index.css @theme. Components consume semantic tokens."

# 7. No Tailwind default color palettes
check "no Tailwind default color palettes" \
  '\b(bg|text|border|ring|from|to|via|outline|fill|stroke|decoration|caret|accent|placeholder|divide|shadow)-(slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-[0-9]+' \
  "" \
  "Tailwind defaults don't match our scale. Use bg-paper-2, text-ink-2, etc."

# 8. opacity-* on disabled
check "no opacity-* for disabled states" \
  'disabled:opacity-[0-9]+|aria-disabled.*opacity-[0-9]+' \
  "" \
  "use disabled:bg-paper-2 disabled:text-ink-3."

# 9. No transition-all
check "no transition-all" \
  '\btransition-all\b' \
  '//.*transition-all|/\*.*transition-all' \
  "use .transition-default."

# 10. No !important
check "no !important" \
  '!\s*important|!important;|className=.*!\[' \
  "" \
  "fix specificity at the source."

# 11. No legacy fg/surface naming (post-migration)
check "no legacy text-text-* or bg-bg" \
  '\b(text-text-(primary|secondary|ghost)|(bg|text|border)-bg([^-a-zA-Z]|$)|bg-surface-(100|200|300)|border-divider([^-a-zA-Z]|$))' \
  "" \
  "run: node scripts/migrate-tokens.mjs --apply"

# 12. font-display deprecated (was Clash, now Instrument Serif italic — only for pull-quotes)
check "no font-display except in .text-quote" \
  '\bfont-display\b' \
  "" \
  "font-display now means Instrument Serif italic. Use font-sans for headings (Geist). Use .text-quote for pull-quotes."

echo
if [ "$fail" -gt 0 ]; then
  red "Design-system check FAILED ($fail of $total)"
  echo "  See DESIGN.md, ANTI-PATTERNS.md, and docs/tokens.md for the canonical tokens."
  exit 1
else
  green "Design-system check passed ($total checks)"
fi
