/**
 * src/http/history.ts (O2) — list past Claude Code sessions for the resume browser.
 *
 * Reads ~/.claude/projects/<encoded>/<session-uuid>.jsonl. Each session's first
 * user message is the preview and its `cwd` is the project directory (so resume
 * can `claude --resume <id>` in the right place). Read-only; best-effort.
 */

import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';

export interface HistorySession {
  id: string;
  cwd: string;
  project: string; // last path segment, for display
  mtimeMs: number;
  preview: string;
}

/** Extract cwd + the first real user prompt from a session jsonl (pure, testable). */
export function parseSessionMeta(jsonlText: string): { cwd: string | null; preview: string } {
  let cwd: string | null = null;
  let preview = '';

  for (const line of jsonlText.split('\n')) {
    const trimmed = line.trim();
    if (trimmed === '') continue;
    let obj: Record<string, unknown>;
    try {
      obj = JSON.parse(trimmed) as Record<string, unknown>;
    } catch {
      continue;
    }

    if (cwd === null && typeof obj['cwd'] === 'string') cwd = obj['cwd'];

    if (preview === '' && obj['type'] === 'user') {
      const msg = obj['message'];
      if (msg !== null && typeof msg === 'object') {
        const content = (msg as Record<string, unknown>)['content'];
        if (typeof content === 'string') {
          preview = content;
        } else if (Array.isArray(content)) {
          for (const part of content) {
            if (part !== null && typeof part === 'object') {
              const p = part as Record<string, unknown>;
              if (p['type'] === 'text' && typeof p['text'] === 'string') {
                preview = p['text'];
                break;
              }
            }
          }
        }
      }
    }

    if (cwd !== null && preview !== '') break;
  }

  return { cwd, preview: preview.replace(/\s+/g, ' ').trim().slice(0, 120) };
}

/** Read up to `max` bytes from the head of a file (async, best-effort). */
async function readHead(file: string, max: number): Promise<string> {
  let fh: fs.FileHandle | undefined;
  try {
    fh = await fs.open(file, 'r');
    const buf = Buffer.alloc(max);
    const { bytesRead } = await fh.read(buf, 0, max, 0);
    return buf.subarray(0, bytesRead).toString('utf8');
  } catch {
    return '';
  } finally {
    await fh?.close().catch(() => undefined);
  }
}

/** Most-recently-modified Claude Code sessions across all projects (async). */
export async function listSessions(limit = 50): Promise<HistorySession[]> {
  const root = path.join(os.homedir(), '.claude', 'projects');
  let dirs: string[];
  try {
    dirs = await fs.readdir(root);
  } catch {
    return [];
  }

  const files: Array<{ id: string; file: string; mtimeMs: number }> = [];
  for (const dir of dirs) {
    const dirPath = path.join(root, dir);
    let names: string[];
    try {
      names = await fs.readdir(dirPath);
    } catch {
      continue;
    }
    for (const name of names) {
      if (!name.endsWith('.jsonl')) continue;
      try {
        const st = await fs.stat(path.join(dirPath, name));
        files.push({
          id: name.slice(0, -'.jsonl'.length),
          file: path.join(dirPath, name),
          mtimeMs: st.mtimeMs,
        });
      } catch {
        // skip unreadable
      }
    }
  }

  files.sort((a, b) => b.mtimeMs - a.mtimeMs);

  const top = files.slice(0, limit);
  return Promise.all(
    top.map(async (f) => {
      const meta = parseSessionMeta(await readHead(f.file, 256 * 1024));
      const cwd = meta.cwd ?? '';
      const project = cwd !== '' ? (cwd.split('/').filter(Boolean).pop() ?? cwd) : 'unknown';
      return { id: f.id, cwd, project, mtimeMs: f.mtimeMs, preview: meta.preview };
    }),
  );
}
