import { createSignal, onCleanup } from "solid-js";
import { ASCII_VIDEO_FPS, ASCII_VIDEO_FRAMES } from "../../dist/ascii-video-animation.js";

// On the home screen the logo slot shares the column with (above it) a flexible
// spacer + a 4-row gap, and (below it) the prompt box and footer. Those lower
// elements do not shrink, so we must keep the logo within `terminalHeight minus
// this reserve` or its top/bottom gets clipped off the screen.
const VERTICAL_CHROME_ROWS = 9;
// Fallbacks used only before the renderer reports a real size.
const FALLBACK_COLUMNS = 120;
const FALLBACK_ROWS = 40;

type BoundingBox = {
  lines: string[];
  left: number;
  width: number;
};

function boundingBox(frame: string): BoundingBox | null {
  const lines = frame.split("\n");
  const nonEmptyRows = lines
    .map((line, index) => (line.trim() ? index : -1))
    .filter(index => index >= 0);

  if (nonEmptyRows.length === 0) return null;

  const top = nonEmptyRows[0];
  const bottom = nonEmptyRows[nonEmptyRows.length - 1];
  const visibleLines = lines.slice(top, bottom + 1).map(line => line.replace(/\s+$/, ""));

  const left = Math.min(
    ...visibleLines.map(line => (line.length ? line.length - line.trimStart().length : Number.POSITIVE_INFINITY))
  );
  const right = Math.max(...visibleLines.map(line => line.length), 0);

  return { lines: visibleLines, left: Number.isFinite(left) ? left : 0, width: Math.max(0, right - left) };
}

// Sample `count` evenly spaced indices across a span of `length` items.
function sampleIndices(length: number, count: number): number[] {
  if (count >= length) return Array.from({ length }, (_, index) => index);
  const indices: number[] = [];
  for (let i = 0; i < count; i++) {
    indices.push(Math.min(length - 1, Math.round((i * (length - 1)) / (count - 1 || 1))));
  }
  return indices;
}

function fitFrame(frame: string, terminalColumns: number, terminalRows: number): string {
  const box = boundingBox(frame);
  if (!box) return "";

  const { lines, left, width } = box;
  const height = lines.length;

  const availableColumns = Math.max(20, terminalColumns - 2);
  const availableRows = Math.max(6, terminalRows - VERTICAL_CHROME_ROWS);

  // Single uniform scale so the whole logo fits without distorting its aspect.
  const scale = Math.min(1, availableColumns / Math.max(1, width), availableRows / height);
  const targetHeight = Math.max(1, Math.round(height * scale));
  const targetWidth = Math.max(1, Math.round(width * scale));

  const rowIndices = sampleIndices(height, targetHeight);
  const columnIndices = sampleIndices(width, targetWidth);

  return rowIndices
    .map(rowIndex => {
      const line = lines[rowIndex];
      return columnIndices
        .map(columnIndex => line[left + columnIndex] ?? " ")
        .join("")
        .replace(/\s+$/, "");
    })
    .join("\n");
}

function AnimatedLogo(props: { renderer?: any }) {
  const [frameIndex, setFrameIndex] = createSignal(0);

  // Track the real terminal size from the TUI renderer (process.stdout.rows is
  // unreliable inside the plugin runtime). Re-fit whenever the terminal resizes.
  const renderer = props.renderer;
  const readSize = () => ({
    columns: Math.max(40, renderer?.width ?? process.stdout.columns ?? FALLBACK_COLUMNS),
    rows: Math.max(10, renderer?.height ?? process.stdout.rows ?? FALLBACK_ROWS),
  });
  const [size, setSize] = createSignal(readSize());

  if (typeof renderer?.on === "function") {
    const onResize = () => setSize(readSize());
    renderer.on("resize", onResize);
    onCleanup(() => {
      if (typeof renderer.off === "function") renderer.off("resize", onResize);
      else if (typeof renderer.removeListener === "function") renderer.removeListener("resize", onResize);
    });
  }

  const frameDelayMs = Math.max(16, Math.round(1000 / ASCII_VIDEO_FPS));
  const timer = setInterval(() => {
    setFrameIndex(index => (index + 1) % ASCII_VIDEO_FRAMES.length);
  }, frameDelayMs);
  onCleanup(() => clearInterval(timer));

  return (
    <text fg="#fbbf24">
      {fitFrame(ASCII_VIDEO_FRAMES[frameIndex()] ?? "", size().columns, size().rows)}
    </text>
  );
}

const tui = async (api: any) => {
  api.slots.register({
    slots: {
      home_logo() {
        return <AnimatedLogo renderer={api.renderer} />;
      },
    },
  });
};

// The TUI plugin loader reads `mod.default` (strict mode) and requires an object
// with a tui() function — a bare `export const tui` is silently skipped.
export default { id: "infinicode-home-logo", tui };
