import { createInterface } from "node:readline";
import { ProcessTerminal, setKeybindings, TUI } from "@earendil-works/pi-tui";
import chalk from "chalk";
import { selectSession } from "./cli/session-picker.js";
import { formatMissingSessionCwdPrompt, } from "./core/session-cwd.js";
import { assertValidSessionId, SessionManager } from "./core/session-manager.js";
import { KeybindingsManager } from "./core/keybindings.js";
import { ExtensionSelectorComponent } from "./modes/interactive/components/extension-selector.js";
import { initTheme, stopThemeWatcher } from "./modes/interactive/theme/theme.js";
import { resolvePath } from "./utils/paths.js";
/**
 * Resolve a session argument to a file path.
 * If it looks like a path, use as-is. Otherwise try to match as session ID prefix.
 */
async function findLocalSessionByExactId(sessionId, cwd, sessionDir) {
    const localSessions = await SessionManager.list(cwd, sessionDir);
    const localMatch = localSessions.find((s) => s.id === sessionId);
    return localMatch ? { type: "local", path: localMatch.path } : undefined;
}
async function resolveSessionPath(sessionArg, cwd, sessionDir) {
    // If it looks like a file path, resolve it before handing it to the session manager.
    if (sessionArg.includes("/") || sessionArg.includes("\\") || sessionArg.endsWith(".jsonl")) {
        return { type: "path", path: resolvePath(sessionArg, cwd) };
    }
    // Try to match as session ID in current project first
    const localSessions = await SessionManager.list(cwd, sessionDir);
    const localMatch = localSessions.find((s) => s.id === sessionArg) ?? localSessions.find((s) => s.id.startsWith(sessionArg));
    if (localMatch) {
        return { type: "local", path: localMatch.path };
    }
    // Try global search across all projects
    const allSessions = await SessionManager.listAll(sessionDir);
    const globalMatch = allSessions.find((s) => s.id === sessionArg) ?? allSessions.find((s) => s.id.startsWith(sessionArg));
    if (globalMatch) {
        return { type: "global", path: globalMatch.path, cwd: globalMatch.cwd };
    }
    // Not found anywhere
    return { type: "not_found", arg: sessionArg };
}
/** Prompt user for yes/no confirmation */
async function promptConfirm(message) {
    return new Promise((resolve) => {
        const rl = createInterface({
            input: process.stdin,
            output: process.stdout,
        });
        rl.question(`${message} [y/N] `, (answer) => {
            rl.close();
            resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
        });
    });
}
export function validateForkFlags(parsed) {
    if (!parsed.fork)
        return;
    const conflictingFlags = [
        parsed.session ? "--session" : undefined,
        parsed.continue ? "--continue" : undefined,
        parsed.resume ? "--resume" : undefined,
        parsed.noSession ? "--no-session" : undefined,
    ].filter((flag) => flag !== undefined);
    if (conflictingFlags.length > 0) {
        console.error(chalk.red(`Error: --fork cannot be combined with ${conflictingFlags.join(", ")}`));
        process.exit(1);
    }
}
export function validateSessionIdFlags(parsed) {
    if (parsed.sessionId === undefined)
        return;
    const conflictingFlags = [
        parsed.session ? "--session" : undefined,
        parsed.continue ? "--continue" : undefined,
        parsed.resume ? "--resume" : undefined,
    ].filter((flag) => flag !== undefined);
    if (conflictingFlags.length > 0) {
        console.error(chalk.red(`Error: --session-id cannot be combined with ${conflictingFlags.join(", ")}`));
        process.exit(1);
    }
    try {
        assertValidSessionId(parsed.sessionId);
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        console.error(chalk.red(`Error: ${message}`));
        process.exit(1);
    }
}
function forkSessionOrExit(sourcePath, cwd, sessionDir, sessionId) {
    try {
        return SessionManager.forkFrom(sourcePath, cwd, sessionDir, { id: sessionId });
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        console.error(chalk.red(`Error: ${message}`));
        process.exit(1);
    }
}
function openSessionOrExit(path, sessionDir) {
    try {
        return SessionManager.open(path, sessionDir);
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        console.error(chalk.red(`Error: ${message}`));
        process.exit(1);
    }
}
export async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
    if (parsed.noSession || parsed.help || parsed.listModels !== undefined) {
        return SessionManager.inMemory(cwd, parsed.sessionId !== undefined ? { id: parsed.sessionId } : undefined);
    }
    if (parsed.fork) {
        if (parsed.sessionId) {
            const existingTarget = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
            if (existingTarget) {
                console.error(chalk.red(`Session already exists with id '${parsed.sessionId}'`));
                process.exit(1);
            }
        }
        const resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);
        switch (resolved.type) {
            case "path":
            case "local":
            case "global":
                return forkSessionOrExit(resolved.path, cwd, sessionDir, parsed.sessionId);
            case "not_found":
                console.error(chalk.red(`No session found matching '${resolved.arg}'`));
                process.exit(1);
        }
    }
    if (parsed.session) {
        const resolved = await resolveSessionPath(parsed.session, cwd, sessionDir);
        switch (resolved.type) {
            case "path":
            case "local":
                return openSessionOrExit(resolved.path, sessionDir);
            case "global": {
                console.log(chalk.yellow(`Session found in different project: ${resolved.cwd}`));
                const shouldFork = await promptConfirm("Fork this session into current directory?");
                if (!shouldFork) {
                    console.log(chalk.dim("Aborted."));
                    process.exit(0);
                }
                return forkSessionOrExit(resolved.path, cwd, sessionDir);
            }
            case "not_found":
                console.error(chalk.red(`No session found matching '${resolved.arg}'`));
                process.exit(1);
        }
    }
    if (parsed.resume) {
        initTheme(settingsManager.getTheme(), true);
        try {
            const selectedPath = await selectSession((onProgress) => SessionManager.list(cwd, sessionDir, onProgress), (onProgress) => SessionManager.listAll(sessionDir, onProgress));
            if (!selectedPath) {
                console.log(chalk.dim("No session selected"));
                process.exit(0);
            }
            return openSessionOrExit(selectedPath, sessionDir);
        }
        finally {
            stopThemeWatcher();
        }
    }
    if (parsed.continue) {
        return SessionManager.continueRecent(cwd, sessionDir);
    }
    if (parsed.sessionId) {
        const existingSession = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
        if (existingSession) {
            return openSessionOrExit(existingSession.path, sessionDir);
        }
        console.error(chalk.yellow(`No session found with id '${parsed.sessionId}'; creating a new session.`));
    }
    return SessionManager.create(cwd, sessionDir, { id: parsed.sessionId });
}
export async function promptForMissingSessionCwd(issue, settingsManager) {
    initTheme(settingsManager.getTheme());
    setKeybindings(KeybindingsManager.create());
    return new Promise((resolve) => {
        const ui = new TUI(new ProcessTerminal(), settingsManager.getShowHardwareCursor());
        ui.setClearOnShrink(settingsManager.getClearOnShrink());
        let settled = false;
        const finish = (result) => {
            if (settled) {
                return;
            }
            settled = true;
            ui.stop();
            resolve(result);
        };
        const selector = new ExtensionSelectorComponent(formatMissingSessionCwdPrompt(issue), ["Continue", "Cancel"], (option) => finish(option === "Continue" ? issue.fallbackCwd : undefined), () => finish(undefined), { tui: ui });
        ui.addChild(selector);
        ui.setFocus(selector);
        ui.start();
    });
}
//# sourceMappingURL=main-session.js.map