import { CommanderError } from "commander";
import { resolveEnvState } from "../application/environment-state.js";
import { loadSummarizeConfig } from "../config.js";
import { parseDurationMs } from "../flags.js";
import { extractSlidesForSource, resolveSlideSettings, resolveSlideSourceFromUrl, } from "../slides/index.js";
import { createOscProgressController } from "../tty/osc-progress.js";
import { startSpinner } from "../tty/spinner.js";
import { createThemeRenderer, resolveThemeNameFromSources, resolveTrueColor, } from "../tty/theme.js";
import { formatVersionLine } from "../version.js";
import { applyHelpStyle, buildSlidesProgram } from "./help.js";
import { writeVerbose } from "./logging.js";
import { createMediaCacheFromConfig } from "./media-cache-state.js";
import { renderSlidesInline } from "./slides-render.js";
import { isRichTty, supportsColor } from "./terminal.js";
function formatTimestamp(seconds) {
    const clamped = Math.max(0, Math.floor(seconds));
    const hours = Math.floor(clamped / 3600);
    const minutes = Math.floor((clamped % 3600) / 60);
    const secs = clamped % 60;
    const mm = String(minutes).padStart(2, "0");
    const ss = String(secs).padStart(2, "0");
    if (hours <= 0)
        return `${minutes}:${ss}`;
    const hh = String(hours).padStart(2, "0");
    return `${hh}:${mm}:${ss}`;
}
function parseRenderMode(raw) {
    const value = typeof raw === "string" ? raw.trim().toLowerCase() : "";
    if (!value || value === "none")
        return "none";
    if (value === "auto" || value === "kitty" || value === "iterm")
        return value;
    throw new Error(`Unsupported --render: ${String(raw)}`);
}
export async function handleSlidesCliRequest({ normalizedArgv, envForRun, stdout, stderr, }) {
    if (normalizedArgv[0]?.toLowerCase() !== "slides")
        return false;
    const program = buildSlidesProgram();
    program.configureOutput({
        writeOut(str) {
            stdout.write(str);
        },
        writeErr(str) {
            stderr.write(str);
        },
    });
    applyHelpStyle(program, envForRun, stdout);
    program.exitOverride();
    try {
        program.parse(normalizedArgv.slice(1), { from: "user" });
    }
    catch (error) {
        if (error instanceof CommanderError && error.code === "commander.helpDisplayed") {
            return true;
        }
        throw error;
    }
    if (program.opts().version) {
        stdout.write(`${formatVersionLine(import.meta.url)}\n`);
        return true;
    }
    const url = program.args[0];
    if (!url) {
        throw new Error("summarize slides requires a URL or local video file.");
    }
    const opts = program.opts();
    const renderMode = parseRenderMode(opts.render);
    if (opts.json && renderMode !== "none") {
        throw new Error("--render is not supported with --json output.");
    }
    const slidesSettings = resolveSlideSettings({
        slides: true,
        slidesOcr: opts.slidesOcr ?? false,
        slidesDir: opts.output ?? opts.slidesDir,
        slidesSceneThreshold: opts.slidesSceneThreshold,
        slidesSceneThresholdExplicit: normalizedArgv.some((arg) => arg === "--slides-scene-threshold" || arg.startsWith("--slides-scene-threshold=")),
        slidesMax: opts.slidesMax,
        slidesMinDuration: opts.slidesMinDuration,
        cwd: process.cwd(),
    });
    if (!slidesSettings) {
        throw new Error("Slides are disabled (enable --slides-ocr or check arguments).");
    }
    const timeoutRaw = typeof opts.timeout === "string" && opts.timeout.trim() ? opts.timeout : "2m";
    const timeoutMs = parseDurationMs(timeoutRaw);
    const { config } = loadSummarizeConfig({ env: envForRun });
    const mediaCache = await createMediaCacheFromConfig({
        envForRun,
        config,
        noMediaCacheFlag: false,
    });
    const themeName = resolveThemeNameFromSources({
        cli: opts.theme,
        env: envForRun.SUMMARIZE_THEME,
        config: config?.ui?.theme,
    });
    envForRun.SUMMARIZE_THEME = themeName;
    const envState = resolveEnvState({ env: envForRun, envForRun, configForCli: config });
    const source = resolveSlideSourceFromUrl(url);
    if (!source) {
        throw new Error("Slides are only supported for YouTube, direct video URLs, or local video files.");
    }
    const verboseEnabled = Boolean(opts.verbose || opts.debug);
    const progressEnabled = isRichTty(stderr) && !opts.json && !verboseEnabled;
    const theme = createThemeRenderer({
        themeName,
        enabled: progressEnabled,
        trueColor: resolveTrueColor(envForRun),
    });
    const renderStatus = (label, detail = "…") => `${theme.label(label)}${theme.dim(detail)}`;
    const renderStatusFromText = (text) => {
        const match = text.match(/^([^:]+):(.*)$/);
        if (!match)
            return renderStatus(text);
        const [, prefix, rest] = match;
        return `${theme.label(prefix.trim())}${theme.dim(`:${rest}`)}`;
    };
    const oscProgress = progressEnabled
        ? createOscProgressController({
            label: "Slides",
            env: envForRun,
            isTty: progressEnabled,
            write: (data) => stderr.write(data),
        })
        : null;
    const spinner = startSpinner({
        text: renderStatus("Extracting slides"),
        enabled: progressEnabled,
        stream: stderr,
        color: theme.palette.spinner,
    });
    const handleSignal = () => {
        try {
            spinner.stopAndClear();
        }
        catch {
            // ignore
        }
        oscProgress?.clear();
    };
    const handleSigint = () => {
        handleSignal();
        process.exit(130);
    };
    const handleSigterm = () => {
        handleSignal();
        process.exit(143);
    };
    if (progressEnabled) {
        process.once("SIGINT", handleSigint);
        process.once("SIGTERM", handleSigterm);
    }
    const verboseColor = supportsColor(stderr, envForRun);
    const logSlides = (message) => {
        writeVerbose(stderr, verboseEnabled, `slides ${message}`, verboseColor, envForRun);
    };
    const onSlidesProgress = (text) => {
        if (progressEnabled) {
            spinner.setText(renderStatusFromText(text));
            const match = text.match(/(\d{1,3})%/);
            const percent = match ? Number(match[1]) : null;
            if (Number.isFinite(percent) && percent !== null) {
                oscProgress?.setPercent("Slides", Math.max(0, Math.min(100, percent)));
            }
            else {
                oscProgress?.setIndeterminate("Slides");
            }
            spinner.refresh?.();
            return;
        }
        if (verboseEnabled) {
            stderr.write(`${text}\n`);
        }
    };
    let slidesExtracted;
    try {
        slidesExtracted = await extractSlidesForSource({
            source,
            settings: slidesSettings,
            noCache: opts.cache === false,
            mediaCache,
            env: envForRun,
            timeoutMs,
            ytDlpPath: envState.ytDlpPath,
            ytDlpCookiesFromBrowser: envState.ytDlpCookiesFromBrowser,
            ffmpegPath: null,
            tesseractPath: null,
            hooks: {
                onSlidesProgress,
                onSlidesLog: logSlides,
            },
        });
    }
    finally {
        spinner.stopAndClear();
        oscProgress?.clear();
        if (progressEnabled) {
            process.off("SIGINT", handleSigint);
            process.off("SIGTERM", handleSigterm);
        }
    }
    if (opts.json) {
        stdout.write(`${JSON.stringify({ ok: true, slides: slidesExtracted }, null, 2)}\n`);
        return true;
    }
    const count = slidesExtracted.slides.length;
    stdout.write(`Slides extracted: ${count}\n`);
    stdout.write(`Slides dir: ${slidesExtracted.slidesDir}\n`);
    if (renderMode !== "none") {
        if (!isRichTty(stdout)) {
            throw new Error("--render requires a TTY stdout.");
        }
        await renderSlidesInline({
            slides: slidesExtracted.slides,
            mode: renderMode,
            env: envForRun,
            stdout,
            labelForSlide: (slide) => `Slide ${slide.index} · ${formatTimestamp(slide.timestamp)} (${slide.imagePath})`,
        });
        return true;
    }
    for (const slide of slidesExtracted.slides) {
        stdout.write(`${slide.index}\t${formatTimestamp(slide.timestamp)}\t${slide.imagePath}\n`);
    }
    return true;
}
//# sourceMappingURL=slides-cli.js.map