import { collectRecentWorkspaceArtifacts, createArtifactZipBundle, formatArtifactSummary, listRecentArtifactReports, totalArtifactSize } from "../../artifacts/artifacts.js";
import { ARTIFACT_DELIVERY_MODES, artifactDeliveryPolicy, isArtifactDeliveryMode } from "../../artifacts/artifact-delivery.js";
import { filterArtifactReports as filterArtifactReportsForCommand } from "../shared/bot-rendering.js";
import { renderArtifactCleanupAction, renderArtifactDeliveryAction, renderArtifactReportsAction, renderArtifactUsageAction } from "../shared/channel-actions.js";
import { deliverChannelAction } from "../shared/channel-runtime.js";
export function createDiscordArtifactCommandHandler(deps) {
    return async (request, argument) => {
        const session = await deps.getSession(request, { deferThreadStart: true });
        const [action, turnId] = argument.trim().split(/\s+/, 2);
        const tokens = argument.trim().split(/\s+/).filter(Boolean);
        const subcommand = tokens[0]?.toLowerCase();
        const info = session.getInfo();
        const workspace = info.workspace;
        if (subcommand === "quota" || subcommand === "usage") {
            await deps.reply(request, renderArtifactUsageAction(await deps.artifactService.usage(workspace)).plain);
            return;
        }
        if (subcommand === "cleanup") {
            const plan = tokens[1]?.toLowerCase() === "run"
                ? await deps.artifactService.cleanupRun(workspace)
                : await deps.artifactService.cleanupPreview(workspace);
            deps.appendActivity(request, {
                status: "info",
                type: "artifact_cleanup",
                threadId: info.threadId,
                workspace,
                agentId: info.agentId,
                detail: `${plan.candidates.length} candidates, ${plan.removedBytes} bytes`,
            });
            await deps.reply(request, renderArtifactCleanupAction(plan).plain);
            return;
        }
        if (subcommand === "delivery") {
            const requested = tokens[1]?.toLowerCase();
            if (!requested) {
                await deps.reply(request, renderArtifactDeliveryAction(deps.getArtifactDeliveryMode?.(request) ?? deps.config.discordArtifactDeliveryMode, "user").plain);
                return;
            }
            if (requested === "default" || requested === "inherit") {
                const mode = await deps.setArtifactDeliveryMode?.(request, null);
                await deps.reply(request, renderArtifactDeliveryAction(mode ?? deps.config.discordArtifactDeliveryMode, "user").plain);
                return;
            }
            if (!isArtifactDeliveryMode(requested)) {
                await deps.reply(request, `Unknown artifact delivery mode. Use one of: ${ARTIFACT_DELIVERY_MODES.join(", ")}, default.`);
                return;
            }
            const mode = await deps.setArtifactDeliveryMode?.(request, requested);
            await deps.reply(request, renderArtifactDeliveryAction(mode ?? requested, "user").plain);
            return;
        }
        const reports = await listRecentArtifactReports(workspace, 10, deps.config.maxFileSize);
        if (reports.length === 0) {
            await deps.reply(request, "No generated artifacts found for this workspace.");
            return;
        }
        if (action) {
            if (action.toLowerCase() === "delete" && turnId) {
                const selected = findArtifactReport(reports, turnId);
                if (!selected) {
                    await deps.reply(request, `No artifact turn found for "${turnId}".`);
                    return;
                }
                const removed = await deps.artifactService.delete(workspace, selected.turnId);
                deps.appendActivity(request, {
                    status: removed ? "info" : "failed",
                    type: "artifact_deleted",
                    threadId: info.threadId,
                    workspace,
                    agentId: info.agentId,
                    detail: selected.turnId,
                });
                await deps.reply(request, removed ? `Deleted artifact turn: ${selected.turnId}` : `Artifact turn not found: ${selected.turnId}`);
                return;
            }
            const filtered = filterArtifactReportsForCommand(reports, argument);
            if (filtered) {
                if (filtered.length === 0) {
                    await deps.reply(request, `No artifacts matched "${argument}".`);
                    return;
                }
                await deliverChannelAction(deps.runtime, request.context, renderDiscordArtifactReports(request.contextKey, filtered));
                return;
            }
            const normalizedAction = action.toLowerCase();
            const shouldZip = normalizedAction === "zip";
            const shouldSend = normalizedAction === "send";
            const selected = findArtifactReport(reports, shouldZip || shouldSend ? turnId : action);
            if (!selected) {
                await deps.reply(request, `No artifact turn found for "${argument}".`);
                return;
            }
            deps.appendActivity(request, {
                status: "info",
                type: shouldZip ? "artifact_zip_sent" : "artifacts_sent",
                threadId: info.threadId,
                workspace,
                agentId: info.agentId,
                detail: selected.turnId,
            });
            if (shouldZip) {
                await deliverDiscordArtifactZip(deps, request, selected);
            }
            else {
                await deliverDiscordArtifactReport(deps, request, selected);
            }
            return;
        }
        await deliverChannelAction(deps.runtime, request.context, renderDiscordArtifactReports(request.contextKey, reports));
    };
}
export async function sendRecentDiscordArtifacts(deps, request, session, since, turnId, policy = artifactDeliveryPolicy(deps.config.discordAutoSendArtifacts ? "auto-files" : "manual-only")) {
    if (!deps.config.artifactsEnabled) {
        return;
    }
    const report = await collectRecentWorkspaceArtifacts(session.getInfo().workspace, {
        since,
        until: new Date(),
        maxFileSize: deps.config.maxFileSize,
        limit: 5,
    });
    if (report.artifacts.length === 0) {
        return;
    }
    const summary = formatArtifactSummary(report.artifacts, report.skippedCount, report.omittedCount);
    if (policy.includeActions) {
        await deliverChannelAction(deps.runtime, request.context, renderDiscordArtifactReports(request.contextKey, [{
                turnId,
                outDir: session.getInfo().workspace,
                updatedAt: new Date(),
                artifacts: report.artifacts,
                skippedCount: report.skippedCount,
                omittedCount: report.omittedCount,
                totalSizeBytes: totalArtifactSize(report.artifacts),
                source: "workspace",
            }]));
    }
    else if (policy.sendSummary && summary) {
        await deps.reply(request, summary);
    }
    if (policy.autoSendZip) {
        const bundle = await createArtifactZipBundle(report.artifacts, session.getInfo().workspace, {
            maxFileSize: deps.config.maxFileSize,
            bundleName: `nordrelay-artifacts-${turnId}.zip`,
        });
        if (bundle)
            await sendDiscordArtifactFile(deps, request, bundle);
    }
    else if (policy.autoSendFiles) {
        for (const artifact of report.artifacts.filter((item) => !policy.imagesOnly || /\.(png|jpe?g|gif|webp)$/i.test(item.name)).slice(0, 5)) {
            await sendDiscordArtifactFile(deps, request, artifact);
        }
    }
    deps.appendActivity(request, {
        status: "info",
        type: "artifacts_sent",
        detail: `${report.artifacts.length} artifacts for ${turnId}`,
        threadId: session.getInfo().threadId,
        workspace: session.getInfo().workspace,
        agentId: session.getInfo().agentId,
    });
}
function renderDiscordArtifactReports(contextKey, reports) {
    const rendered = renderArtifactReportsAction(reports);
    return {
        ...rendered,
        buttons: reports.slice(0, 5).map((report, index) => [
            { label: `${index + 1} Send`, action: `discord_artifact_send:${contextKey}:${report.turnId}` },
            { label: `${index + 1} ZIP`, action: `discord_artifact_zip:${contextKey}:${report.turnId}` },
            { label: `${index + 1} Delete`, action: `discord_artifact_delete:${contextKey}:${report.turnId}` },
        ]),
    };
}
function findArtifactReport(reports, requested) {
    const value = requested?.trim();
    if (!value || value.toLowerCase() === "latest") {
        return reports[0];
    }
    return reports.find((report) => report.turnId === value || report.turnId.startsWith(value));
}
async function deliverDiscordArtifactZip(deps, request, report) {
    const bundle = await createArtifactZipBundle(report.artifacts, report.outDir, {
        maxFileSize: deps.config.maxFileSize,
        bundleName: `nordrelay-artifacts-${report.turnId}.zip`,
    });
    if (!bundle) {
        await deps.reply(request, "Could not create a ZIP bundle for this artifact turn.");
        return;
    }
    if (!deps.runtime.sendFile) {
        await deps.reply(request, "This Discord runtime cannot send artifact files.");
        return;
    }
    await deps.runtime.sendFile(request.context, { localPath: bundle.localPath, name: bundle.name });
    await deps.reply(request, `Sent ZIP artifact bundle: ${bundle.name}`);
}
async function deliverDiscordArtifactReport(deps, request, report) {
    if (report.artifacts.length === 0 && report.skippedCount === 0 && !report.omittedCount) {
        await deps.reply(request, "No generated artifacts found for this turn.");
        return;
    }
    let failedCount = 0;
    let bundledArtifact = null;
    if (report.artifacts.length > 5) {
        bundledArtifact = await createArtifactZipBundle(report.artifacts, report.outDir, {
            maxFileSize: deps.config.maxFileSize,
        });
    }
    const delivered = bundledArtifact ? [bundledArtifact] : report.artifacts;
    for (const artifact of delivered) {
        if (!await sendDiscordArtifactFile(deps, request, artifact)) {
            failedCount += 1;
        }
    }
    const summary = formatArtifactSummary(report.artifacts, report.skippedCount + failedCount, report.omittedCount);
    if (summary) {
        const bundleNote = bundledArtifact ? `\nSent as ZIP: ${bundledArtifact.name}` : "";
        await deps.reply(request, `${summary}${bundleNote}`);
    }
}
async function sendDiscordArtifactFile(deps, request, artifact) {
    if (!deps.runtime.sendFile) {
        await deps.reply(request, "This Discord runtime cannot send artifact files.");
        return false;
    }
    try {
        await deps.runtime.sendFile(request.context, { localPath: artifact.localPath, name: artifact.name });
        return true;
    }
    catch (error) {
        console.error(`Failed to send Discord artifact ${artifact.name}:`, error);
        return false;
    }
}
