import * as React from 'react';
import { useKnobTheme } from '../core/theme';

// Fourteen-segment geometry in a local 10 x 18 digit cell.
// Outer ring: a top, b top-right, c bottom-right, d bottom, e bottom-left,
// f top-left. Middle bar: g1 left, g2 right. Center verticals: i top, l
// bottom. Diagonals: h TL, j TR, k BL, m BR.

const W = 10;
const H = 18;
const DEFAULT_GAP = 3.4;
const BASE_HALF = 1.05;
const INSET = 0.45;

const hSeg = (y: number, x1: number, x2: number, half: number): string => {
  const a = x1 + INSET;
  const b = x2 - INSET;
  return `${a},${y} ${a + half},${y - half} ${b - half},${y - half} ${b},${y} ${b - half},${y + half} ${a + half},${y + half}`;
};

const vSeg = (x: number, y1: number, y2: number, half: number): string => {
  const a = y1 + INSET;
  const b = y2 - INSET;
  return `${x},${a} ${x + half},${a + half} ${x + half},${b - half} ${x},${b} ${x - half},${b - half} ${x - half},${a + half}`;
};

type Seg14 =
  | 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
  | 'g1' | 'g2' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm';

const buildPoly = (half: number): Partial<Record<Seg14, string>> => ({
  a: hSeg(1, 1, 9, half),
  d: hSeg(17, 1, 9, half),
  g1: hSeg(9, 1, 5, half),
  g2: hSeg(9, 5, 9, half),
  f: vSeg(1, 1, 9, half),
  b: vSeg(9, 1, 9, half),
  e: vSeg(1, 9, 17, half),
  c: vSeg(9, 9, 17, half),
  i: vSeg(5, 1, 9, half),
  l: vSeg(5, 9, 17, half),
});

/** Diagonals render as thick lines: [x1, y1, x2, y2]. */
const DIAG: Partial<Record<Seg14, [number, number, number, number]>> = {
  h: [2.2, 2.7, 4.1, 7.2],
  j: [7.8, 2.7, 5.9, 7.2],
  k: [4.1, 10.8, 2.2, 15.3],
  m: [5.9, 10.8, 7.8, 15.3],
};

const CHARS: Record<string, Seg14[]> = {
  '0': ['a', 'b', 'c', 'd', 'e', 'f'],
  '1': ['b', 'c'],
  '2': ['a', 'b', 'g1', 'g2', 'e', 'd'],
  '3': ['a', 'b', 'c', 'd', 'g1', 'g2'],
  '4': ['f', 'g1', 'g2', 'b', 'c'],
  '5': ['a', 'f', 'g1', 'g2', 'c', 'd'],
  '6': ['a', 'f', 'g1', 'g2', 'e', 'c', 'd'],
  '7': ['a', 'b', 'c'],
  '8': ['a', 'b', 'c', 'd', 'e', 'f', 'g1', 'g2'],
  '9': ['a', 'b', 'c', 'd', 'f', 'g1', 'g2'],
  A: ['a', 'b', 'c', 'e', 'f', 'g1', 'g2'],
  B: ['a', 'b', 'c', 'd', 'i', 'l', 'g2'],
  C: ['a', 'd', 'e', 'f'],
  D: ['a', 'b', 'c', 'd', 'i', 'l'],
  E: ['a', 'd', 'e', 'f', 'g1', 'g2'],
  F: ['a', 'e', 'f', 'g1', 'g2'],
  G: ['a', 'c', 'd', 'e', 'f', 'g2'],
  H: ['b', 'c', 'e', 'f', 'g1', 'g2'],
  I: ['a', 'd', 'i', 'l'],
  J: ['b', 'c', 'd', 'e'],
  K: ['e', 'f', 'g1', 'j', 'm'],
  L: ['d', 'e', 'f'],
  M: ['b', 'c', 'e', 'f', 'h', 'j'],
  N: ['b', 'c', 'e', 'f', 'h', 'm'],
  O: ['a', 'b', 'c', 'd', 'e', 'f'],
  P: ['a', 'b', 'e', 'f', 'g1', 'g2'],
  Q: ['a', 'b', 'c', 'd', 'e', 'f', 'm'],
  R: ['a', 'b', 'e', 'f', 'g1', 'g2', 'm'],
  S: ['a', 'c', 'd', 'f', 'g1', 'g2'],
  T: ['a', 'i', 'l'],
  U: ['b', 'c', 'd', 'e', 'f'],
  V: ['e', 'f', 'j', 'k'],
  W: ['b', 'c', 'e', 'f', 'k', 'm'],
  X: ['h', 'j', 'k', 'm'],
  Y: ['h', 'j', 'l'],
  Z: ['a', 'd', 'j', 'k'],
  // '$' is an S with the center verticals lit through it.
  $: ['a', 'c', 'd', 'f', 'g1', 'g2', 'i', 'l'],
  '-': ['g1', 'g2'],
  '_': ['d'],
  '=': ['g1', 'g2', 'd'],
  '+': ['g1', 'g2', 'i', 'l'],
  '*': ['g1', 'g2', 'h', 'i', 'j', 'k', 'l', 'm'],
  '/': ['j', 'k'],
  '\\': ['h', 'm'],
  '?': ['a', 'b', 'g2', 'l'],
  ' ': [],
};

const ALL_SEGMENTS = Object.keys({ ...buildPoly(BASE_HALF), ...DIAG }) as Seg14[];

export interface AlphaDisplayProps {
  /** Text: A–Z, 0–9, space, - _ = + * / \ ? $ : % and '.' (attaches to the previous cell). */
  value: string;
  /** Fixed number of character cells; the text is padded/cropped to fit. */
  chars?: number;
  align?: 'left' | 'right';
  /** Character height in px. Default: 22. */
  height?: number;
  /** Lit color. Defaults to the theme's `ledAmber`. */
  color?: string;
  /**
   * Segment thickness multiplier — thickens strokes so the display holds up at
   * small heights. Default: 1.
   */
  weight?: number;
  /** Inter-cell spacing. Default: 3.4. */
  gap?: number;
  /** Panel background. Set to 'none' to disable. */
  background?: string;
  /** Opacity of unlit segments. Default: 0.08. */
  ghostOpacity?: number;
  /** Italic skew in degrees. Default: 6. */
  skew?: number;
  /** LED glow strength (0 disables). Default: 1.4. */
  glow?: number;
  padding?: number;
  /** Dim the display uniformly (matches disabled controls). */
  disabled?: boolean;
  className?: string;
  style?: React.CSSProperties;
}

/**
 * Fourteen-segment alphanumeric LED display — preset names, modes, messages.
 * The alphanumeric sibling of `SegmentDisplay`.
 */
export const AlphaDisplay: React.FC<AlphaDisplayProps> = ({
  value,
  chars,
  align = 'left',
  height = 22,
  color,
  weight = 1,
  gap = DEFAULT_GAP,
  background = '#0a0d0c',
  ghostOpacity = 0.08,
  skew = 6,
  glow = 1.4,
  padding = 6,
  disabled = false,
  className,
  style,
}) => {
  const theme = useKnobTheme();
  const lit = color ?? theme.ledAmber;
  const filterId = React.useId();
  const half = BASE_HALF * weight;
  const POLY = buildPoly(half);
  const dot = half * 1.35;
  const diagWidth = 1.5 * weight;

  let text = value.toUpperCase();
  if (chars !== undefined) {
    const cellCount = text.replace(/[.]/g, '').length;
    if (cellCount < chars) {
      const pad = ' '.repeat(chars - cellCount);
      text = align === 'right' ? pad + text : text + pad;
    } else if (cellCount > chars) {
      let kept = 0;
      let out = '';
      for (const ch of text) {
        if (ch !== '.' && kept === chars) break;
        if (ch !== '.') kept++;
        out += ch;
      }
      text = out;
    }
  }

  const cells: React.ReactNode[] = [];
  let x = 0;
  let key = 0;
  for (const ch of text) {
    if (ch === '.') {
      cells.push(
        <rect key={key++} x={x - dot} y={H - dot * 2} width={dot * 2} height={dot * 2} rx={dot * 0.5} fill={lit} />,
      );
      x += dot * 2 + Math.min(gap * 0.6, 2.6);
      continue;
    }
    if (ch === ':') {
      const cx = x + dot;
      cells.push(
        <g key={key++}>
          <rect x={cx - dot} y={H * 0.3 - dot} width={dot * 2} height={dot * 2} rx={dot * 0.5} fill={lit} />
          <rect x={cx - dot} y={H * 0.72 - dot} width={dot * 2} height={dot * 2} rx={dot * 0.5} fill={lit} />
        </g>,
      );
      x += dot * 2 + gap;
      continue;
    }
    if (ch === '%') {
      // Slash with a dot at each end — the percent idiom.
      cells.push(
        <g key={key++} transform={`translate(${x} 0)`}>
          <line x1={2} y1={16} x2={8} y2={2} stroke={lit} strokeWidth={diagWidth} strokeLinecap="butt" />
          <circle cx={2.8} cy={4} r={dot * 1.05} fill={lit} />
          <circle cx={7.2} cy={14} r={dot * 1.05} fill={lit} />
        </g>,
      );
      x += W + gap;
      continue;
    }
    const on = new Set(CHARS[ch] ?? []);
    const parts: React.ReactNode[] = [];
    for (const seg of ALL_SEGMENTS) {
      const isOn = on.has(seg);
      if (!isOn && ghostOpacity <= 0) continue;
      const opacity = isOn ? 1 : ghostOpacity;
      const poly = POLY[seg];
      if (poly) {
        parts.push(<polygon key={seg} points={poly} fill={lit} opacity={opacity} />);
      } else {
        const [x1, y1, x2, y2] = DIAG[seg]!;
        parts.push(
          <line
            key={seg}
            x1={x1}
            y1={y1}
            x2={x2}
            y2={y2}
            stroke={lit}
            strokeWidth={diagWidth}
            strokeLinecap="butt"
            opacity={opacity}
          />,
        );
      }
    }
    cells.push(
      <g key={key++} transform={`translate(${x} 0)`}>
        {parts}
      </g>,
    );
    x += W + gap;
  }

  const contentW = Math.max(x - gap, 0);
  const scale = height / H;
  const w = contentW * scale + padding * 2 + height * 0.15;
  const h = height + padding * 2;

  return (
    <svg
      width={w}
      height={h}
      viewBox={`0 0 ${w} ${h}`}
      className={className}
      style={{ ...(disabled ? { opacity: 0.45 } : undefined), ...style }}
      data-disabled={disabled ? '' : undefined}
      role="img"
      aria-label={value}
    >
      {glow > 0 && (
        <defs>
          <filter id={filterId} x="-40%" y="-40%" width="180%" height="180%">
            <feGaussianBlur stdDeviation={glow} result="blur" />
            <feMerge>
              <feMergeNode in="blur" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>
        </defs>
      )}
      {background !== 'none' && <rect x={0} y={0} width={w} height={h} rx={4} fill={background} />}
      <g
        transform={`translate(${padding + height * 0.12} ${padding}) scale(${scale})`}
        filter={glow > 0 ? `url(#${filterId})` : undefined}
      >
        {skew ? <g transform={`skewX(${-Math.abs(skew)})`}>{cells}</g> : cells}
      </g>
    </svg>
  );
};
