/**
 * Map<threadKey, ThreadChat[]> — chats Pavel started via "Work on this".
 *
 * Each thread can have multiple chats (different work sessions over time).
 * Newest first.
 *
 * TODO(cleanup): on read, drop entries whose sessionId no longer exists in
 * ~/.claude/projects/ — happens when user deletes a .jsonl outside the app.
 * For now we leave dead refs; they'll just resolve to a 404 in the UI which
 * is recoverable.
 *
 * TODO(continue-last): expose a "Continue last thread chat" alternative to
 * always-creating-new. For now each "Work on this" click creates a fresh
 * conversation, which keeps each work session a self-contained artifact.
 */
import { readFileSync, writeFileSync, existsSync } from "node:fs";
import { THREAD_CHATS_FILE } from "./paths";

export type ThreadChat = {
  sessionId: string;
  startedAt: string; // ISO
  /** Optional human label set when the chat was created (defaults to "Working on: <text-prefix>"). */
  label?: string;
};

export function loadThreadChats(): Record<string, ThreadChat[]> {
  if (!existsSync(THREAD_CHATS_FILE)) return {};
  try {
    const data = JSON.parse(readFileSync(THREAD_CHATS_FILE, "utf8"));
    return data && typeof data === "object" ? data : {};
  } catch { return {}; }
}

export function saveThreadChats(map: Record<string, ThreadChat[]>) {
  writeFileSync(THREAD_CHATS_FILE, JSON.stringify(map, null, 2));
}

/** Append a new chat to the thread's list (newest first). */
export function linkThreadChat(threadKey: string, chat: ThreadChat) {
  const map = loadThreadChats();
  const arr = map[threadKey] ? [chat, ...map[threadKey]] : [chat];
  map[threadKey] = arr;
  saveThreadChats(map);
}

/** Reverse lookup: which thread does this sessionId belong to (if any)? */
export function threadKeyForSession(sessionId: string): string | null {
  const map = loadThreadChats();
  for (const [key, chats] of Object.entries(map)) {
    if (chats.some((c) => c.sessionId === sessionId)) return key;
  }
  return null;
}

/** Find the most recent non-archived chat linked to this thread, with the
 *  project + cwd needed to resume it. Returns null if there are none. */
export function findLatestActiveChatForThread(threadKey: string):
  | { sessionId: string; projectRaw: string; cwd: string }
  | null {
  const map = loadThreadChats();
  const chats = map[threadKey];
  if (!chats || chats.length === 0) return null;
  // Imports here to avoid top-level cycle with chats.ts.
  const { readdirSync, statSync, existsSync, readFileSync } = require("node:fs") as typeof import("node:fs");
  const { join } = require("node:path") as typeof import("node:path");
  const { CLAUDE_PROJECTS_DIR, ARCHIVED_CHATS_FILE } = require("./paths") as typeof import("./paths");
  const { readSessionMeta } = require("./chats") as typeof import("./chats");

  // Load archived set once.
  let archived = new Set<string>();
  try {
    if (existsSync(ARCHIVED_CHATS_FILE)) {
      const list = JSON.parse(readFileSync(ARCHIVED_CHATS_FILE, "utf8"));
      if (Array.isArray(list)) archived = new Set(list.map((e: any) => e.sessionId));
    }
  } catch { /* ignore */ }

  // Newest first per linkThreadChat invariant — return the first one we can resolve.
  for (const chat of chats) {
    if (archived.has(chat.sessionId)) continue;
    // Walk projects to find the .jsonl. Cheap because Claude only has dozens.
    try {
      for (const proj of readdirSync(CLAUDE_PROJECTS_DIR)) {
        const file = join(CLAUDE_PROJECTS_DIR, proj, `${chat.sessionId}.jsonl`);
        try {
          const st = statSync(file);
          if (st.isFile() && st.size > 0) {
            const meta = readSessionMeta(file);
            return { sessionId: chat.sessionId, projectRaw: proj, cwd: meta.cwd || "" };
          }
        } catch { /* not in this project */ }
      }
    } catch { /* projects dir unreadable */ }
  }
  return null;
}
