'use strict';

const readline = require('readline');
const { blue, gray } = require('../utils/colors');

function isFullwidthCodePoint(code) {
  return (
    code >= 0x1100 &&
    (code <= 0x115f ||
      code === 0x2329 ||
      code === 0x232a ||
      (code >= 0x2e80 && code <= 0xa4cf && code !== 0x303f) ||
      (code >= 0xac00 && code <= 0xd7a3) ||
      (code >= 0xf900 && code <= 0xfaff) ||
      (code >= 0xfe10 && code <= 0xfe19) ||
      (code >= 0xfe30 && code <= 0xfe6f) ||
      (code >= 0xff00 && code <= 0xff60) ||
      (code >= 0xffe0 && code <= 0xffe6) ||
      (code >= 0x1f300 && code <= 0x1f64f) ||
      (code >= 0x1f900 && code <= 0x1f9ff))
  );
}

function stringWidth(text) {
  if (!text) return 0;
  let width = 0;
  for (const char of text) {
    const code = char.codePointAt(0);
    if (code == null) continue;
    width += isFullwidthCodePoint(code) ? 2 : 1;
  }
  return width;
}

function padEndDisplay(text, targetWidth) {
  const current = stringWidth(text);
  if (current >= targetWidth) return text;
  return text + ' '.repeat(targetWidth - current);
}

function truncateDisplay(text, width) {
  if (!text || width <= 0) return '';
  let out = '';
  let w = 0;
  for (const ch of text) {
    const c = ch.codePointAt(0);
    const cw = c != null && isFullwidthCodePoint(c) ? 2 : 1;
    if (w + cw > width) break;
    out += ch;
    w += cw;
  }
  return out;
}

function fitLine(text, width) {
  if (!text) return '';
  if (stringWidth(text) <= width) return text;
  return truncateDisplay(text, Math.max(0, width - 1));
}

async function runResumeMenu({ rl, items }) {
  rl.pause();
  rl.line = '';
  rl.cursor = 0;
  readline.clearLine(process.stdout, 0);
  readline.cursorTo(process.stdout, 0);
  // Keep stdin flowing for keypress events while readline is paused.
  readline.emitKeypressEvents(process.stdin);
  if (process.stdin.isTTY) process.stdin.setRawMode(true);
  process.stdin.resume();

  let selected = 0;
  let start = 0;

  function render() {
    const rows = process.stdout.rows || 24;
    const cols = process.stdout.columns || 80;
    const leftPad = '  ';
    const gap = '  ';
    const timeWidth = Math.min(
      16,
      Math.max(8, ...items.map((it) => (it.time ? stringWidth(it.time) : 0)))
    );
    const headerLines = [
      `${leftPad}Resume a previous session`,
      '',
      `${leftPad} ${padEndDisplay('Updated', timeWidth)}${gap}Conversation`,
    ];
    const footer = 'enter to resume     esc to start new     ctrl + c to quit     ↑/↓ to browse';
    const headerCount = headerLines.length;
    const footerCount = 1;
    const listHeight = Math.max(1, rows - headerCount - footerCount);

    if (selected < start) start = selected;
    if (selected >= start + listHeight) start = selected - listHeight + 1;

    const lines = [];
    headerLines.forEach((line) => lines.push(fitLine(line, cols)));

    for (let i = 0; i < listHeight; i++) {
      const idx = start + i;
      if (idx < items.length) {
        const prefix = idx === selected ? '>' : ' ';
        const time = items[idx].time || '';
        const title = items[idx].title || '';
        const line = `${leftPad}${prefix}${padEndDisplay(time, timeWidth)}${gap}${title}`;
        lines.push(idx === selected ? blue(fitLine(line, cols)) : fitLine(line, cols));
      } else {
        lines.push('');
      }
    }

    lines.push(gray(fitLine(footer, cols)));

    process.stdout.write('\x1b[2J\x1b[H');
    process.stdout.write(lines.join('\n'));
  }

  render();

  return new Promise((resolve) => {
    let resolved = false;
    const cleanup = () => {
      process.stdin.off('keypress', onKey);
      if (process.stdin.isTTY) process.stdin.setRawMode(true);
      process.stdin.resume();
      try {
        rl.resume();
      } catch (_) {}
      process.stdout.write('\x1b[2J\x1b[H');
    };

    const finish = (val) => {
      if (resolved) return;
      resolved = true;
      cleanup();
      resolve(val);
    };

    const onKey = (str, key) => {
      if (key && key.ctrl && key.name === 'c') {
        process.stdout.write('\n');
        process.exit(0);
      }
      if (key && key.name === 'up') {
        if (items.length) {
          selected = Math.max(0, selected - 1);
          render();
        }
        return;
      }
      if (key && key.name === 'down') {
        if (items.length) {
          selected = Math.min(items.length - 1, selected + 1);
          render();
        }
        return;
      }
      if (key && key.name === 'return') {
        const chosen = items[selected];
        finish({ type: 'resume', id: chosen ? chosen.id : null });
        return;
      }
      if (key && key.name === 'escape') {
        finish({ type: 'new' });
        return;
      }
    };
    process.stdin.on('keypress', onKey);
  });
}

module.exports = { runResumeMenu };
