import { and, eq } from "drizzle-orm";
import { mkdirSync, rmSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { providerAccounts } from "../db/schema.js";
import { uuidv7 } from "../db/uuidv7.js";
import { AcpProvider } from "../providers/acp-provider.js";
export class ProviderAccountService {
    db;
    registry;
    accountsRoot;
    definitions;
    constructor(db, registry, definitions, accountsRoot = join(homedir(), ".jait", "provider-accounts")) {
        this.db = db;
        this.registry = registry;
        this.accountsRoot = accountsRoot;
        this.definitions = new Map(definitions.map((definition) => [definition.id, definition]));
    }
    load() {
        for (const account of this.db.select().from(providerAccounts).all()) {
            this.register(account);
        }
    }
    list(userId) {
        return this.db.select().from(providerAccounts).where(eq(providerAccounts.userId, userId)).all();
    }
    listTypes() {
        return [...this.definitions.values()]
            .filter((definition) => definition.auth !== false)
            .map((definition) => ({
            providerType: definition.id,
            name: definition.name,
            description: definition.description,
        }));
    }
    get(id, userId) {
        return this.db.select().from(providerAccounts).where(and(eq(providerAccounts.id, id), eq(providerAccounts.userId, userId))).get() ?? null;
    }
    create(userId, providerType, label) {
        const definition = this.definitions.get(providerType);
        if (!definition || definition.auth === false) {
            throw new Error(`Provider accounts are not supported for ${providerType}`);
        }
        const normalizedLabel = this.normalizeLabel(label);
        const now = new Date().toISOString();
        const account = {
            id: `${providerType}-${uuidv7()}`,
            userId,
            providerType,
            label: normalizedLabel,
            createdAt: now,
            updatedAt: now,
        };
        this.db.insert(providerAccounts).values(account).run();
        this.register(account);
        return account;
    }
    async rename(id, userId, label) {
        const account = this.get(id, userId);
        if (!account)
            return null;
        const normalizedLabel = this.normalizeLabel(label);
        const updatedAt = new Date().toISOString();
        this.db.update(providerAccounts).set({ label: normalizedLabel, updatedAt })
            .where(and(eq(providerAccounts.id, id), eq(providerAccounts.userId, userId))).run();
        const updated = { ...account, label: normalizedLabel, updatedAt };
        const provider = this.registry.getForUser(id, userId);
        const definition = this.definitions.get(account.providerType);
        if (provider && definition)
            provider.info.name = `${definition.name} — ${normalizedLabel}`;
        return updated;
    }
    async delete(id, userId) {
        const account = this.get(id, userId);
        if (!account)
            return false;
        await this.registry.unregister(id);
        this.db.delete(providerAccounts).where(and(eq(providerAccounts.id, id), eq(providerAccounts.userId, userId))).run();
        rmSync(this.accountHome(id), { recursive: true, force: true });
        return true;
    }
    register(account) {
        const definition = this.definitions.get(account.providerType);
        if (!definition)
            return;
        const accountHome = this.accountHome(account.id);
        mkdirSync(accountHome, { recursive: true, mode: 0o700 });
        const env = {
            ...definition.env,
            HOME: accountHome,
            USERPROFILE: accountHome,
            XDG_CONFIG_HOME: join(accountHome, ".config"),
            XDG_DATA_HOME: join(accountHome, ".local", "share"),
            XDG_CACHE_HOME: join(accountHome, ".cache"),
            NPM_CONFIG_CACHE: definition.env?.NPM_CONFIG_CACHE
                ?? process.env.NPM_CONFIG_CACHE
                ?? process.env.npm_config_cache
                ?? join(homedir(), ".npm"),
            ...(account.providerType === "codex"
                ? { CODEX_HOME: accountHome, OPENAI_API_KEY: "" }
                : {}),
            ...(account.providerType === "claude-code"
                ? { CLAUDE_CONFIG_DIR: join(accountHome, ".claude"), ANTHROPIC_API_KEY: "" }
                : {}),
        };
        this.registry.register(new AcpProvider({
            ...definition,
            id: account.id,
            providerType: account.providerType,
            ownerUserId: account.userId,
            name: `${definition.name} — ${account.label}`,
            env,
        }));
    }
    accountHome(id) {
        return join(this.accountsRoot, id);
    }
    normalizeLabel(label) {
        const normalizedLabel = label.trim();
        if (!normalizedLabel)
            throw new Error("Account label is required");
        if (normalizedLabel.length > 80)
            throw new Error("Account label must be 80 characters or fewer");
        return normalizedLabel;
    }
}
//# sourceMappingURL=provider-accounts.js.map