import type { CSSProperties } from "react";

type RetroLedMarqueeProps = {
  text: string;
  className?: string;
};

const MATRIX_ROWS = 7;
const MATRIX_COLUMNS = 56;
const REPEAT_GAP_COLUMNS = 12;

const GLYPHS: Record<string, string[]> = {
  A: ["01110", "10001", "10001", "11111", "10001", "10001", "10001"],
  B: ["11110", "10001", "10001", "11110", "10001", "10001", "11110"],
  D: ["11110", "10001", "10001", "10001", "10001", "10001", "11110"],
  E: ["11111", "10000", "10000", "11110", "10000", "10000", "11111"],
  G: ["01111", "10000", "10000", "10111", "10001", "10001", "01111"],
  H: ["10001", "10001", "10001", "11111", "10001", "10001", "10001"],
  I: ["11111", "00100", "00100", "00100", "00100", "00100", "11111"],
  M: ["10001", "11011", "10101", "10101", "10001", "10001", "10001"],
  N: ["10001", "11001", "10101", "10011", "10001", "10001", "10001"],
  O: ["01110", "10001", "10001", "10001", "10001", "10001", "01110"],
  R: ["11110", "10001", "10001", "11110", "10100", "10010", "10001"],
  T: ["11111", "00100", "00100", "00100", "00100", "00100", "00100"],
  Y: ["10001", "10001", "01010", "00100", "00100", "00100", "00100"],
  " ": ["000", "000", "000", "000", "000", "000", "000"],
};

function getGlyph(character: string) {
  return GLYPHS[character] ?? GLYPHS[" "];
}

function getMessageColumns(text: string) {
  return text
    .toUpperCase()
    .split("")
    .reduce((total, character, index, characters) => {
      const glyph = getGlyph(character);
      const glyphWidth = glyph[0]?.length ?? 0;
      const spacer = index === characters.length - 1 ? 0 : 1;

      return total + glyphWidth + spacer;
    }, 0);
}

function buildLitDots(text: string) {
  const dots: Array<{ key: string; row: number; column: number }> = [];
  let columnOffset = 0;

  text
    .toUpperCase()
    .split("")
    .forEach((character, characterIndex, characters) => {
      const glyph = getGlyph(character);
      const glyphWidth = glyph[0]?.length ?? 0;

      glyph.forEach((row, rowIndex) => {
        row.split("").forEach((cell, columnIndex) => {
          if (cell !== "1") {
            return;
          }

          dots.push({
            key: `${characterIndex}-${rowIndex}-${columnIndex}`,
            row: rowIndex + 1,
            column: columnOffset + columnIndex + 1,
          });
        });
      });

      columnOffset += glyphWidth;

      if (characterIndex < characters.length - 1) {
        columnOffset += 1;
      }
    });

  return dots;
}

function RetroLedMessage({ text, hidden = false }: { text: string; hidden?: boolean }) {
  const litDots = buildLitDots(text);

  return (
    <div className="retro-led-message" aria-hidden={hidden}>
      {litDots.map((dot) => (
        <span
          key={dot.key}
          className="retro-led-dot retro-led-active-dot"
          style={{
            gridRow: dot.row,
            gridColumn: dot.column,
          }}
        />
      ))}
    </div>
  );
}

export function RetroLedMarquee({ text, className }: RetroLedMarqueeProps) {
  const backgroundDots = Array.from({ length: MATRIX_COLUMNS * MATRIX_ROWS }, (_, index) => index);
  const messageColumns = getMessageColumns(text);

  return (
    <div
      className={["retro-led-panel", className].filter(Boolean).join(" ")}
      aria-label={text}
      style={
        {
          "--retro-led-visible-columns": MATRIX_COLUMNS,
          "--retro-led-visible-rows": MATRIX_ROWS,
          "--retro-led-message-columns": messageColumns,
          "--retro-led-repeat-gap-columns": REPEAT_GAP_COLUMNS,
        } as CSSProperties
      }
    >
      <div className="retro-led-viewport">
        <div className="retro-led-background" aria-hidden="true">
          {backgroundDots.map((dot) => (
            <span key={dot} className="retro-led-dot retro-led-background-dot" />
          ))}
        </div>
        <div className="retro-led-track">
          <RetroLedMessage text={text} />
          <div className="retro-led-spacer" aria-hidden="true" />
          <RetroLedMessage text={text} hidden />
        </div>
      </div>
    </div>
  );
}
