/**
 * Icon — the shared icon primitive and controlled vocabulary (arch 09 §5).
 *
 * Astrolabe is label-first: an icon is added only when it does real work, usually
 * alongside text (arch 09 §5.1). This module is the single source of truth for the
 * icon set — one glyph per meaning, app-wide (§5.2). Adding an icon means adding a
 * `IconName` + a registry entry here, never inlining an SVG in a component.
 *
 * The glyphs are traced from IBM Carbon's icon set (32×32 grid, fill-based — they
 * read as outlines but are filled shapes). Carbon is inspiration, not a dependency.
 * Every glyph draws with `fill: currentColor`, so it inherits its text colour and
 * themes for free.
 *
 * Icons are decorative by default (`aria-hidden`): the control around them carries
 * the accessible name (text label, or an `aria-label` on an icon-only button — APG
 * button pattern). Never rely on an icon alone to name a control.
 */

import type { ReactNode } from 'react';
import styles from './Icon.module.css';

/** The controlled icon vocabulary (arch 09 §5.2). One entry = one meaning. */
export type IconName =
  | 'close' // close / dismiss (universal, icon-only)
  | 'moon' // theme: switch to dark (universal, icon-only)
  | 'sun' // theme: switch to light (universal, icon-only)
  | 'dataset' // "references a dataset" — Carbon DataTable
  | 'delete' // delete — Carbon TrashCan
  | 'add' // add / create-new — Carbon Add
  | 'chart' // build / open a chart — rising columns on a baseline (pane-icon style)
  | 'search' // live library search — Carbon Search
  | 'settings' // per-pane settings disclosure (gear) — Carbon Settings
  | 'import' // import a workspace file — Carbon Upload (a file goes in)
  | 'export' // export the workspace to a file — Carbon Download (a file comes out)
  | 'info' // about / information — Carbon Information (outline)
  | 'revert' // revert draft to last published — Carbon Reset
  | 'structure' // composition-structure wireframe disclosure (preview toolbar) — nested view blocks
  | 'layers' // layered-composition badge (wireframe) — two stacked planes (one shared space)
  // Mark sub-family (composition wireframe leaves) — a simplified glyph of a unit
  // view's mark type, so which-is-which reads at a glance. Vega-Lite mark synonyms
  // collapse onto these via `markIconName` (CompositionWireframe); unknown → generic.
  | 'mark-bar'
  | 'mark-line'
  | 'mark-area'
  | 'mark-point'
  | 'mark-arc'
  | 'mark-rect'
  | 'mark-tick'
  | 'mark-rule'
  | 'mark-text'
  | 'mark-generic'
  // Pane-toggle sub-family (spec §01A): a panel frame with one region filled, so the
  // glyph shows *which* pane it controls by position (left / centre / right).
  | 'pane-library' // toggle the library pane (left)
  | 'pane-editor' // toggle the editor pane (centre)
  | 'pane-preview' // toggle the preview pane (right)
  // Status sub-family (arch 09 §5.2) — Carbon's FILLED notification glyphs, coloured
  // by status (not text). A redundant non-colour severity channel (WCAG 1.4.1): the
  // triangle shape-codes warning apart from the round error/success/info.
  | 'status-error' // Carbon ErrorFilled
  | 'status-warning' // Carbon WarningAltFilled (triangle)
  | 'status-success' // Carbon CheckmarkFilled
  | 'status-info'; // Carbon InformationFilled

/** Carbon icon scale (arch 09 §5.3). 16px (sm) is the default, paired to 14px body. */
type IconSize = 'sm' | 'md' | 'lg' | 'xl';

/** Inner SVG geometry per glyph, on Carbon's 0 0 32 32 grid. fill comes from CSS. */
const GLYPHS: Record<IconName, ReactNode> = {
  close: (
    <polygon points="17.4141 16 24 9.4141 22.5859 8 16 14.5859 9.4143 8 8 9.4141 14.5859 16 8 22.5859 9.4143 24 16 17.4141 22.5859 24 24 22.5859 17.4141 16" />
  ),
  add: <polygon points="17,15 17,8 15,8 15,15 8,15 8,17 15,17 15,24 17,24 17,17 24,17 24,15" />,
  // Rising columns on a baseline — drawn in the pane-icon rect style (not a Carbon
  // trace) so it reads at 16px next to the pane glyphs.
  chart: (
    <>
      <rect x="4" y="24" width="24" height="2" />
      <rect x="8" y="16" width="4" height="8" />
      <rect x="14" y="10" width="4" height="14" />
      <rect x="20" y="6" width="4" height="18" />
    </>
  ),
  // Carbon Search — magnifying glass, the active-search affordance (council SEARCH).
  search: (
    <path d="M29,27.5859l-7.5521-7.5521a11.0177,11.0177,0,1,0-1.4141,1.4141L27.5859,29ZM4,13a9,9,0,1,1,9,9A9.01,9.01,0,0,1,4,13Z" />
  ),
  settings: (
    <>
      <path d="M27,16.76c0-.25,0-.5,0-.76s0-.51,0-.77l1.92-1.68A2,2,0,0,0,29.3,11L26.94,7a2,2,0,0,0-1.73-1,2,2,0,0,0-.64.1l-2.43.82a11.35,11.35,0,0,0-1.31-.75l-.51-2.52a2,2,0,0,0-2-1.61H13.64a2,2,0,0,0-2,1.61l-.51,2.52a11.48,11.48,0,0,0-1.32.75L7.43,6.06A2,2,0,0,0,6.79,6,2,2,0,0,0,5.06,7L2.7,11a2,2,0,0,0,.41,2.51L5,15.24c0,.25,0,.5,0,.76s0,.51,0,.77L3.11,18.45A2,2,0,0,0,2.7,21L5.06,25a2,2,0,0,0,1.73,1,2,2,0,0,0,.64-.1l2.43-.82a11.35,11.35,0,0,0,1.31.75l.51,2.52a2,2,0,0,0,2,1.61h4.72a2,2,0,0,0,2-1.61l.51-2.52a11.48,11.48,0,0,0,1.32-.75l2.42.82a2,2,0,0,0,.64.1,2,2,0,0,0,1.73-1L29.3,21a2,2,0,0,0-.41-2.51ZM25.21,24l-3.43-1.16a8.86,8.86,0,0,1-2.71,1.57L18.36,28H13.64l-.71-3.55a9.36,9.36,0,0,1-2.7-1.57L6.79,24,4.43,20l2.72-2.4a8.9,8.9,0,0,1,0-3.13L4.43,12,6.79,8l3.43,1.16a8.86,8.86,0,0,1,2.71-1.57L13.64,4h4.72l.71,3.55a9.36,9.36,0,0,1,2.7,1.57L25.21,8,27.57,12l-2.72,2.4a8.9,8.9,0,0,1,0,3.13L27.57,20Z" />
      <path d="M16,22a6,6,0,1,1,6-6A5.94,5.94,0,0,1,16,22Zm0-10a3.91,3.91,0,0,0-4,4,3.91,3.91,0,0,0,4,4,3.91,3.91,0,0,0,4-4A3.91,3.91,0,0,0,16,12Z" />
    </>
  ),
  delete: (
    <>
      <rect x="12" y="12" width="2" height="12" />
      <rect x="18" y="12" width="2" height="12" />
      <path d="M4,6V8H6V28a2,2,0,0,0,2,2H24a2,2,0,0,0,2-2V8h2V6ZM8,28V8H24V28Z" />
      <rect x="12" y="2" width="8" height="2" />
    </>
  ),
  // Carbon Upload — open tray with an up arrow (a file is brought into the app).
  import: (
    <>
      <path d="M26,24v4H6V24H4v4a2,2,0,0,0,2,2H26a2,2,0,0,0,2-2V24Z" />
      <path d="M6,12l1.41,1.41L15,5.83V24h2V5.83l7.59,7.59L26,12,16,2Z" />
    </>
  ),
  // Carbon Download — open tray with a down arrow (a file is written out).
  export: (
    <>
      <path d="M26,24v4H6V24H4v4a2,2,0,0,0,2,2H26a2,2,0,0,0,2-2V24Z" />
      <path d="M26,14l-1.41-1.41L17,20.17V2H15V20.17l-7.59-7.58L6,14l10,10Z" />
    </>
  ),
  // Carbon Information (outline) — ring + "i".
  info: (
    <>
      <path d="M17,22V14H13v2h2v6H12v2h8V22Z" />
      <path d="M16,8a1.5,1.5,0,1,0,1.5,1.5A1.5,1.5,0,0,0,16,8Z" />
      <path d="M16,30A14,14,0,1,1,30,16,14,14,0,0,1,16,30ZM16,4A12,12,0,1,0,28,16,12,12,0,0,0,16,4Z" />
    </>
  ),
  // Carbon Reset — a circular arrow, "return to the prior state".
  revert: (
    <path d="M18,28A12,12,0,1,0,6,16v6.2L2.41,18.59,1,20l6,6,6-6L11.59,18.59,8,22.2V16A10,10,0,1,1,18,26Z" />
  ),
  dataset: (
    <>
      <rect x="8" y="18" width="4" height="2" />
      <rect x="14" y="18" width="4" height="2" />
      <rect x="8" y="14" width="4" height="2" />
      <rect x="14" y="22" width="4" height="2" />
      <rect x="20" y="14" width="4" height="2" />
      <rect x="20" y="22" width="4" height="2" />
      <path d="M27,3H5A2.0025,2.0025,0,0,0,3,5V27a2.0025,2.0025,0,0,0,2,2H27a2.0025,2.0025,0,0,0,2-2V5A2.0025,2.0025,0,0,0,27,3Zm0,2,0,4H5V5ZM5,27V11H27l0,16Z" />
    </>
  ),
  // Panel frame (x4–28 / y6–26, 2px border) with one third filled. The filled bar's
  // position maps to the pane: left = library, centre = editor, right = preview.
  'pane-library': (
    <>
      <rect x="4" y="6" width="24" height="2" />
      <rect x="4" y="24" width="24" height="2" />
      <rect x="4" y="6" width="2" height="20" />
      <rect x="26" y="6" width="2" height="20" />
      <rect x="7" y="10" width="4" height="12" />
    </>
  ),
  'pane-editor': (
    <>
      <rect x="4" y="6" width="24" height="2" />
      <rect x="4" y="24" width="24" height="2" />
      <rect x="4" y="6" width="2" height="20" />
      <rect x="26" y="6" width="2" height="20" />
      <rect x="14" y="10" width="4" height="12" />
    </>
  ),
  'pane-preview': (
    <>
      <rect x="4" y="6" width="24" height="2" />
      <rect x="4" y="24" width="24" height="2" />
      <rect x="4" y="6" width="2" height="20" />
      <rect x="26" y="6" width="2" height="20" />
      <rect x="21" y="10" width="4" height="12" />
    </>
  ),
  // Composition structure: a panel frame (matching the pane family) holding nested
  // view blocks — two side by side over one wide — the wireframe in miniature.
  structure: (
    <>
      <rect x="4" y="6" width="24" height="2" />
      <rect x="4" y="24" width="24" height="2" />
      <rect x="4" y="6" width="2" height="20" />
      <rect x="26" y="6" width="2" height="20" />
      <rect x="9" y="10" width="6" height="5" />
      <rect x="17" y="10" width="6" height="5" />
      <rect x="9" y="17" width="14" height="5" />
    </>
  ),
  // Two offset planes — a layer is one space with several marks stacked in z-order.
  layers: (
    <>
      <rect x="6" y="6" width="15" height="15" fill="none" stroke="currentColor" strokeWidth={2} />
      <rect
        x="11"
        y="11"
        width="15"
        height="15"
        fill="none"
        stroke="currentColor"
        strokeWidth={2}
      />
    </>
  ),
  // Mark glyphs: simplified renderings of each Vega-Lite mark, drawn on the same
  // 32-grid. Stroke-based where a line reads truer than a fill (line/rule/generic).
  'mark-bar': (
    <>
      <rect x="5" y="14" width="5" height="14" />
      <rect x="13" y="8" width="5" height="20" />
      <rect x="21" y="18" width="5" height="10" />
    </>
  ),
  'mark-line': (
    <polyline
      points="4,22 11,13 18,17 28,6"
      fill="none"
      stroke="currentColor"
      strokeWidth={2.5}
      strokeLinecap="round"
      strokeLinejoin="round"
    />
  ),
  'mark-area': <path d="M4,28 L4,17 L12,11 L20,16 L28,7 L28,28 Z" />,
  'mark-point': (
    <>
      <circle cx="9" cy="20" r="2.6" />
      <circle cx="16" cy="12" r="2.6" />
      <circle cx="22" cy="22" r="2.6" />
      <circle cx="25" cy="9" r="2.6" />
    </>
  ),
  // A three-quarter pie wedge (one quadrant empty) reads as arc/pie at a glance.
  'mark-arc': <path d="M16,16 L16,4 A12,12 0 1,1 4,16 Z" />,
  'mark-rect': (
    <>
      <rect x="5" y="9" width="6" height="6" />
      <rect x="13" y="9" width="6" height="6" />
      <rect x="21" y="9" width="6" height="6" />
      <rect x="5" y="17" width="6" height="6" />
      <rect x="13" y="17" width="6" height="6" />
      <rect x="21" y="17" width="6" height="6" />
    </>
  ),
  'mark-tick': (
    <>
      <rect x="6" y="10" width="2" height="12" />
      <rect x="12" y="10" width="2" height="12" />
      <rect x="18" y="10" width="2" height="12" />
      <rect x="24" y="10" width="2" height="12" />
    </>
  ),
  'mark-rule': (
    <line
      x1="5"
      y1="24"
      x2="27"
      y2="8"
      fill="none"
      stroke="currentColor"
      strokeWidth={2.5}
      strokeLinecap="round"
    />
  ),
  'mark-text': (
    <>
      <rect x="6" y="8" width="20" height="3" />
      <rect x="6" y="15" width="14" height="3" />
      <rect x="6" y="22" width="18" height="3" />
    </>
  ),
  'mark-generic': (
    <rect x="5" y="6" width="22" height="20" fill="none" stroke="currentColor" strokeWidth={2} />
  ),
  moon: (
    <path d="M13.5025,5.4136A15.0755,15.0755,0,0,0,25.096,23.6082a11.1134,11.1134,0,0,1-7.9749,3.3893c-.1385,0-.2782.0051-.4178,0A11.0944,11.0944,0,0,1,13.5025,5.4136M14.98,3a1.0024,1.0024,0,0,0-.1746.0156A13.0959,13.0959,0,0,0,16.63,28.9973c.1641.006.3282,0,.4909,0a13.0724,13.0724,0,0,0,10.702-5.5556,1.0094,1.0094,0,0,0-.7833-1.5644A13.08,13.08,0,0,1,15.8892,4.38,1.0149,1.0149,0,0,0,14.98,3Z" />
  ),
  sun: (
    <>
      <rect x="15" y="2" width="2" height="5" />
      <rect
        x="21.6675"
        y="6.8536"
        width="4.958"
        height="1.9998"
        transform="translate(1.5191 19.3744) rotate(-45)"
      />
      <rect x="25" y="15" width="5" height="2" />
      <rect
        x="23.1466"
        y="21.6675"
        width="1.9998"
        height="4.958"
        transform="translate(-10.0018 24.1465) rotate(-45)"
      />
      <rect x="15" y="25" width="2" height="5" />
      <rect
        x="5.3745"
        y="23.1466"
        width="4.958"
        height="1.9998"
        transform="translate(-14.7739 12.6256) rotate(-45)"
      />
      <rect x="2" y="15" width="5" height="2" />
      <rect
        x="6.8536"
        y="5.3745"
        width="1.9998"
        height="4.958"
        transform="translate(-3.253 7.8535) rotate(-45)"
      />
      <path d="M16,12a4,4,0,1,1-4,4,4.0045,4.0045,0,0,1,4-4m0-2a6,6,0,1,0,6,6,6,6,0,0,0-6-6Z" />
    </>
  ),
  // Filled status glyphs: the symbol is a winding-rule knockout in the solid shape,
  // so it shows the surface colour through (Carbon's filled notification family).
  'status-error': (
    <path d="M16,2A13.914,13.914,0,0,0,2,16,13.914,13.914,0,0,0,16,30,13.914,13.914,0,0,0,30,16,13.914,13.914,0,0,0,16,2Zm5.4449,21L9,10.5557,10.5557,9,23,21.4448Z" />
  ),
  'status-warning': (
    <path d="M16.002,6.1714h-.004L4.6487,27.9966,4.6506,28H27.3494l.0019-.0034ZM14.875,12h2.25v9h-2.25ZM16,26a1.5,1.5,0,1,1,1.5-1.5A1.5,1.5,0,0,1,16,26Z" />
  ),
  'status-success': (
    <path d="M16,2A14,14,0,1,0,30,16,14,14,0,0,0,16,2ZM14,21.5908l-5-5L10.5906,15,14,18.4092,21.41,11l1.5957,1.5859Z" />
  ),
  'status-info': (
    <path d="M16,2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Zm0,6a1.5,1.5,0,1,1-1.5,1.5A1.5,1.5,0,0,1,16,8Zm4,16.125H12v-2.25h2.875v-5.75H13v-2.25h4.125v8H20Z" />
  ),
};

export interface IconProps {
  name: IconName;
  /** Carbon scale; defaults to `sm` (16px) — the body-text default. */
  size?: IconSize;
  /** Extra class for layout-level overrides (margins, colour). */
  className?: string;
}

export function Icon({ name, size = 'sm', className }: IconProps) {
  return (
    <svg
      className={`${styles.icon} ${styles[size]}${className ? ` ${className}` : ''}`}
      viewBox="0 0 32 32"
      // Decorative: the enclosing control names itself (arch 09 §5.1).
      aria-hidden="true"
      focusable={false}
    >
      {GLYPHS[name]}
    </svg>
  );
}
