/**
 * POWERED BY DAXNUTS - Easter egg for OpenCode + Kimi K2.5
 *
 * A heartfelt tribute to dax (@thdxr) for providing free Kimi K2.5 access via OpenCode.
 */

import { type Component, type TUI, visibleWidth } from "@singularity-forge/tui";
import { theme } from "../theme/theme.js";

// 32x32 RGB image of dax, hex encoded (3 bytes per pixel)
const DAX_HEX =
	"[encoded data, 6144 characters]";

const WIDTH = 32;
const HEIGHT = 32;

function parseImage(): number[][][] {
	const pixels: number[][][] = [];
	for (let y = 0; y < HEIGHT; y++) {
		const row: number[][] = [];
		for (let x = 0; x < WIDTH; x++) {
			const idx = (y * WIDTH + x) * 6;
			const r = parseInt(DAX_HEX.slice(idx, idx + 2), 16);
			const g = parseInt(DAX_HEX.slice(idx + 2, idx + 4), 16);
			const b = parseInt(DAX_HEX.slice(idx + 4, idx + 6), 16);
			row.push([r, g, b]);
		}
		pixels.push(row);
	}
	return pixels;
}

function rgb(r: number, g: number, b: number, bg = false): string {
	return `\x1b[${bg ? 48 : 38};2;${r};${g};${b}m`;
}

const RESET = "\x1b[0m";

function buildImage(): string[] {
	const pixels = parseImage();
	const lines: string[] = [];

	// Use half-block chars: ▄ with bg=top pixel, fg=bottom pixel
	for (let row = 0; row < HEIGHT; row += 2) {
		let line = "";
		for (let x = 0; x < WIDTH; x++) {
			const top = pixels[row][x];
			const bottom = pixels[row + 1]?.[x] ?? top;
			line += `${rgb(bottom[0], bottom[1], bottom[2])}${rgb(top[0], top[1], top[2], true)}▄`;
		}
		line += RESET;
		lines.push(line);
	}
	return lines;
}

export class DaxnutsComponent implements Component {
	private ui: TUI;
	private image: string[];
	private interval: ReturnType<typeof setInterval> | null = null;
	private tick = 0;
	private maxTicks = 25; // ~2 seconds at 80ms
	private cachedLines: string[] = [];
	private cachedWidth = 0;
	private cachedTick = -1;

	constructor(ui: TUI) {
		this.ui = ui;
		this.image = buildImage();
		this.startAnimation();
	}

	invalidate(): void {
		this.cachedWidth = 0;
	}

	private startAnimation(): void {
		this.interval = setInterval(() => {
			this.tick++;
			if (this.tick >= this.maxTicks) {
				this.stopAnimation();
			}
			this.cachedWidth = 0;
			this.ui.requestRender();
		}, 80);
	}

	private stopAnimation(): void {
		if (this.interval) {
			clearInterval(this.interval);
			this.interval = null;
		}
	}

	render(width: number): string[] {
		if (width === this.cachedWidth && this.cachedTick === this.tick) {
			return this.cachedLines;
		}

		const t = theme;
		const lines: string[] = [];

		const center = (s: string) => {
			const visible = visibleWidth(s);
			const left = Math.max(0, Math.floor((width - visible) / 2));
			return " ".repeat(left) + s;
		};

		lines.push("");

		// Scanline reveal effect: show rows progressively
		const revealedRows = Math.min(
			this.image.length,
			Math.floor((this.tick / this.maxTicks) * (this.image.length + 3)),
		);

		for (let i = 0; i < this.image.length; i++) {
			if (i < revealedRows) {
				lines.push(center(this.image[i]));
			} else {
				// Show scan line
				if (i === revealedRows) {
					const scanline = "▓".repeat(WIDTH);
					lines.push(center(rgb(100, 200, 255) + scanline + RESET));
				} else {
					lines.push(center(" ".repeat(WIDTH)));
				}
			}
		}

		lines.push("");

		// Fade in text after image is revealed
		const textPhase = Math.max(0, this.tick - this.maxTicks * 0.6);
		if (textPhase > 0 || this.tick >= this.maxTicks) {
			lines.push(center(t.fg("accent", "Free Kimi K2.5 via OpenCode Zen")));
			lines.push(center(t.fg("success", '"Powered by daxnuts"')));
			lines.push(center(t.fg("muted", "— @thdxr")));
		} else {
			lines.push("");
			lines.push("");
			lines.push("");
		}

		lines.push("");
		if (textPhase > 2 || this.tick >= this.maxTicks) {
			lines.push(center(t.fg("dim", "Try OpenCode")));
			// URL removed — was pointing to an incorrect destination
			lines.push(center(t.fg("mdLink", "opencode.ai")));
		} else {
			lines.push("");
			lines.push("");
		}
		lines.push("");

		this.cachedLines = lines;
		this.cachedWidth = width;
		this.cachedTick = this.tick;
		return lines;
	}

	dispose(): void {
		this.stopAnimation();
	}
}
