// Terminal image display using Kitty or iTerm2 protocols.
// Uses supports-terminal-graphics for detection; rendering has no npm deps.

import supportsTerminalGraphics from 'supports-terminal-graphics';

/**
 * Auto-pick a nearest-neighbor scale (2x, 3x, or 4x) so the image
 * is large enough to see but fits roughly within the terminal.
 */
function autoScale(imageWidth: number, imageHeight: number): number {
  const termCols = process.stdout.columns || 80;
  // Assume ~8px per cell width; aim to fill about half the terminal width
  const targetPx = termCols * 4;
  const scale = Math.max(1, Math.min(4, Math.round(targetPx / imageWidth)));
  return scale;
}

/**
 * Detect terminal type and display a PNG image inline.
 * imageWidth/imageHeight are the original pixel dimensions (avoids re-decoding for Kitty/iTerm2).
 * Returns true if the image was displayed, false otherwise.
 */
export function displayImageInTerminal(pngData: Uint8Array, imageWidth?: number, imageHeight?: number): boolean {
  if (!process.stdout.isTTY) return false;

  // If dimensions not provided, read from PNG header
  if (!imageWidth || !imageHeight) {
    const dims = readPNGDimensions(pngData);
    imageWidth = dims.width;
    imageHeight = dims.height;
  }
  if (!imageWidth || !imageHeight) return false;

  const scale = autoScale(imageWidth, imageHeight);
  const support = supportsTerminalGraphics.stdout;

  if (support.kitty) {
    displayKitty(pngData, imageWidth, imageHeight, scale);
    return true;
  }

  if (support.iterm2) {
    displayITerm2(pngData, imageWidth, imageHeight, scale);
    return true;
  }

  /*
  if (support.sixel) {
    displaySixel(pngData);
    return true;
  }
  */

  return false;
}

/** Read width/height from a PNG IHDR chunk without full decode. */
function readPNGDimensions(data: Uint8Array): { width: number; height: number } {
  if (data.length >= 24 && data[12] === 0x49 && data[13] === 0x48 && data[14] === 0x44 && data[15] === 0x52) {
    return { width: readU32(data, 16), height: readU32(data, 20) };
  }
  return { width: 0, height: 0 };
}

/**
 * Kitty graphics protocol: transmit PNG data as base64 chunks.
 * c= and r= specify display size in terminal cells (~8px wide, ~16px tall).
 * https://sw.kovidgoyal.net/kitty/graphics-protocol/
 */
function displayKitty(pngData: Uint8Array, w: number, h: number, scale: number): void {
  const b64 = Buffer.from(pngData).toString('base64');
  const chunkSize = 4096;
  const cols = Math.ceil(w * scale / 8);
  const rows = Math.ceil(h * scale / 16);

  for (let i = 0; i < b64.length; i += chunkSize) {
    const chunk = b64.slice(i, i + chunkSize);
    const more = i + chunkSize < b64.length ? 1 : 0;
    if (i === 0) {
      process.stdout.write(`\x1b_Gf=100,a=T,c=${cols},r=${rows},m=${more};${chunk}\x1b\\`);
    } else {
      process.stdout.write(`\x1b_Gm=${more};${chunk}\x1b\\`);
    }
  }
  process.stdout.write('\n');
}

/**
 * iTerm2 inline image protocol with pixel-level width/height.
 * https://iterm2.com/documentation-images.html
 */
function displayITerm2(pngData: Uint8Array, w: number, h: number, scale: number): void {
  const b64 = Buffer.from(pngData).toString('base64');
  const pw = w * scale;
  const ph = h * scale;
  process.stdout.write(`\x1b]1337;File=inline=1;size=${pngData.length};width=${pw}px;height=${ph}px:${b64}\x07\n`);
}

function readU32(data: Uint8Array, offset: number): number {
  return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0;
}

