import { spawnSync } from "node:child_process";
import { writeConfig, writePassword, removeConfig, checkAddressBinding, writeBindingConfig, } from "../lib/credentials.js";
import { inferProvider, getProviderNotes } from "../lib/providers.js";
import * as imap from "../lib/imap.js";
import * as smtp from "../lib/smtp.js";
/**
 * Task 432 — operator-initiated ingestion replaces the background poll.
 * Strips any pre-existing email-fetch crontab line written by an older
 * setup so previously-configured installs stop auto-polling on next
 * email-setup. Returns true when a stale line was removed.
 */
function stripStaleEmailFetchCron() {
    try {
        const listResult = spawnSync("crontab", ["-l"], {
            encoding: "utf-8",
            stdio: ["pipe", "pipe", "pipe"],
        });
        if (listResult.status !== 0)
            return false;
        const existing = listResult.stdout ?? "";
        if (!existing.includes("email-fetch"))
            return false;
        const cleaned = existing
            .split("\n")
            .filter((line) => !line.includes("email-fetch"))
            .join("\n");
        const writeResult = spawnSync("crontab", ["-"], {
            input: cleaned.endsWith("\n") ? cleaned : `${cleaned}\n`,
            encoding: "utf-8",
            stdio: ["pipe", "pipe", "pipe"],
        });
        return writeResult.status === 0;
    }
    catch {
        return false;
    }
}
export async function emailSetup(params) {
    const { email, password, accountId } = params;
    // Infer provider defaults if hosts not explicitly provided
    const provider = inferProvider(email);
    const providerNotes = getProviderNotes(email) ?? undefined;
    const agentAddress = params.agentAddress?.trim() || email;
    const config = {
        email,
        agentAddress,
        imapHost: params.imapHost ?? provider?.imapHost ?? "",
        imapPort: params.imapPort ?? provider?.imapPort ?? 993,
        imapSecurity: params.imapSecurity ?? provider?.imapSecurity ?? "tls",
        smtpHost: params.smtpHost ?? provider?.smtpHost ?? "",
        smtpPort: params.smtpPort ?? provider?.smtpPort ?? 587,
        smtpSecurity: params.smtpSecurity ?? provider?.smtpSecurity ?? "starttls",
    };
    // Reject if hosts are still empty (unknown provider, user didn't provide)
    if (!config.imapHost) {
        return {
            success: false,
            message: `Cannot infer IMAP host for ${email}. Provide imapHost and smtpHost explicitly.`,
            providerNotes,
        };
    }
    if (!config.smtpHost) {
        return {
            success: false,
            message: `Cannot infer SMTP host for ${email}. Provide smtpHost explicitly.`,
            providerNotes,
        };
    }
    // Validate 1:1 agent-email binding: each address maps to exactly one agent
    const agentSlug = params.agentSlug ?? "admin";
    const conflicting = await checkAddressBinding(agentAddress, agentSlug);
    if (conflicting) {
        return {
            success: false,
            message: `Email address ${agentAddress} is already bound to agent "${conflicting}". Each email address can only be used by one agent.`,
        };
    }
    // Warn about likely misconfigured port/security combinations
    if (config.imapPort === 993 && config.imapSecurity === "starttls") {
        return {
            success: false,
            message: "Port 993 uses implicit TLS, not STARTTLS. Use imapSecurity: 'tls' with port 993, or port 143 with 'starttls'.",
        };
    }
    if (config.smtpPort === 465 && config.smtpSecurity === "starttls") {
        return {
            success: false,
            message: "Port 465 uses implicit TLS, not STARTTLS. Use smtpSecurity: 'tls' with port 465, or port 587 with 'starttls'.",
        };
    }
    // Test IMAP connectivity
    const imapError = await imap.testConnection(config, password);
    if (imapError) {
        return { success: false, message: imapError, providerNotes };
    }
    // Test SMTP connectivity
    const smtpError = await smtp.testConnection(config, password);
    if (smtpError) {
        return { success: false, message: smtpError, providerNotes };
    }
    // Both tests passed — persist credentials
    // Write graph node first (easier to clean up), then password file
    try {
        await writeConfig(accountId, config);
    }
    catch (err) {
        return {
            success: false,
            message: `IMAP and SMTP connections verified, but failed to store config: ${err instanceof Error ? err.message : String(err)}`,
        };
    }
    try {
        writePassword(password);
    }
    catch (err) {
        // Rollback graph node — best effort, don't mask the original error
        try {
            await removeConfig(accountId);
        }
        catch { /* rollback failed — next setup will MERGE over it */ }
        return {
            success: false,
            message: `IMAP and SMTP connections verified, but failed to store password file: ${err instanceof Error ? err.message : String(err)}`,
        };
    }
    // Set agent binding and poll config
    let bindingOk = true;
    try {
        await writeBindingConfig(accountId, agentSlug, params.pollIntervalMinutes ?? 5);
    }
    catch {
        bindingOk = false;
    }
    // Task 432 — background polling retired. Strip any stale email-fetch
    // crontab line from an earlier setup so previously-configured installs
    // stop auto-polling. Operator now drives ingestion via the email-ingest
    // skill (email-fetch + email-ingest tools).
    const cronStripped = stripStaleEmailFetchCron();
    // Get inbox count as a confirmation signal
    let inboxCount;
    try {
        inboxCount = await imap.getInboxCount(config, password);
    }
    catch {
        // Non-fatal — setup still succeeded
    }
    const aliasNote = agentAddress !== email ? ` Agent address: ${agentAddress} (auth: ${email}).` : "";
    const bindingNote = bindingOk
        ? ` Bound to agent ${agentSlug}.`
        : ` Email configured but agent binding could not be set — run email-setup again.`;
    const ingestNote = ` Ingestion is operator-initiated: ask the agent to "check my emails" to review and decide on new messages.`;
    const cronNote = cronStripped
        ? ` Removed a stale background-fetch crontab line from an earlier setup.`
        : "";
    return {
        success: true,
        message: `Email configured successfully for ${email}.${aliasNote} IMAP and SMTP connections verified.${inboxCount !== undefined ? ` Inbox has ${inboxCount} messages.` : ""}${bindingNote}${ingestNote}${cronNote}`,
        inboxCount,
        providerNotes,
    };
}
//# sourceMappingURL=email-setup.js.map