import { createRequire } from "node:module";
import { existsSync } from "node:fs";
import { join } from "node:path";
import { homedir } from "node:os";
import { isCommandAvailable } from "../../../utils/executable.js";
import { ACPAgentClient, } from "./acp-agent.js";
const require = createRequire(import.meta.url);
const resolvedPiAcpPath = require.resolve("pi-acp");
const PI_CAPABILITIES = {
    supportsStreaming: true,
    supportsSessionPersistence: true,
    supportsDynamicModes: true,
    supportsMcpServers: false,
    supportsReasoningStream: true,
    supportsToolInvocations: true,
};
// Pi tool kind corrections: pi-acp maps 'bash' to kind 'other' instead of 'execute'.
const PI_TOOL_KIND_MAP = {
    bash: "execute",
};
function normalizePiModelLabel(label) {
    return label.trim().replace(/[_\s]+/g, " ");
}
export function transformPiModels(models) {
    return models.map((model) => {
        if (!model.label.includes("/")) {
            return model;
        }
        const segments = model.label.split("/").filter((segment) => segment.length > 0);
        const rawLabel = segments.at(-1);
        if (!rawLabel) {
            return model;
        }
        return {
            ...model,
            label: normalizePiModelLabel(rawLabel),
            description: model.description ?? model.label,
        };
    });
}
function transformPiToolSnapshot(snapshot) {
    if (snapshot.kind === "other" && snapshot.title && PI_TOOL_KIND_MAP[snapshot.title]) {
        return { ...snapshot, kind: PI_TOOL_KIND_MAP[snapshot.title] };
    }
    return snapshot;
}
/**
 * Pi-acp reports thinking levels (off/minimal/low/medium/high/xhigh) as ACP
 * session modes rather than as configOptions with category 'thought_level'.
 * This transformer remaps them so the base ACP class treats them as thinking
 * options instead of permission modes.
 */
export function transformPiSessionResponse(response) {
    const modes = response.modes;
    if (!modes?.availableModes?.length) {
        return response;
    }
    const thinkingOption = {
        id: "thought_level",
        name: "Thinking",
        type: "select",
        category: "thought_level",
        currentValue: modes.currentModeId ?? "medium",
        options: modes.availableModes.map((mode) => ({
            value: mode.id,
            name: mode.name.replace(/^Thinking:\s*/i, ""),
            description: mode.description,
        })),
    };
    return {
        ...response,
        modes: undefined,
        configOptions: [
            thinkingOption,
            ...(response.configOptions ?? []),
        ],
    };
}
function isThoughtLevelFeature(feature) {
    return feature.type === "select" && feature.id === "thought_level";
}
function normalizePiFeatures(features, thinkingOptionId) {
    if (!features) {
        return features;
    }
    return features.map((feature) => {
        if (!isThoughtLevelFeature(feature)) {
            return feature;
        }
        return {
            ...feature,
            value: thinkingOptionId ?? feature.value,
        };
    });
}
class PiACPAgentSession {
    get id() {
        return this.inner.id;
    }
    get features() {
        return normalizePiFeatures(this.inner.features, this.thinkingOptionId);
    }
    constructor(inner, config) {
        this.inner = inner;
        this.provider = inner.provider;
        this.capabilities = inner.capabilities;
        this.thinkingOptionId = config.thinkingOptionId ?? null;
    }
    async run(prompt, options) {
        return this.inner.run(prompt, options);
    }
    async startTurn(prompt, options) {
        return this.inner.startTurn(prompt, options);
    }
    subscribe(callback) {
        return this.inner.subscribe(callback);
    }
    async *streamHistory() {
        yield* this.inner.streamHistory();
    }
    async getRuntimeInfo() {
        const runtimeInfo = await this.inner.getRuntimeInfo();
        const thinkingOptionId = runtimeInfo.modeId ?? runtimeInfo.thinkingOptionId ?? this.thinkingOptionId;
        this.thinkingOptionId = thinkingOptionId ?? null;
        return {
            ...runtimeInfo,
            modeId: null,
            thinkingOptionId: thinkingOptionId ?? null,
        };
    }
    async getAvailableModes() {
        return [];
    }
    async getCurrentMode() {
        return null;
    }
    async setMode(modeId) {
        void modeId;
        throw new Error("Pi does not expose selectable modes");
    }
    getPendingPermissions() {
        return this.inner.getPendingPermissions();
    }
    async respondToPermission(requestId, response) {
        await this.inner.respondToPermission(requestId, response);
    }
    describePersistence() {
        return this.inner.describePersistence();
    }
    async interrupt() {
        await this.inner.interrupt();
    }
    async close() {
        await this.inner.close();
    }
    async listCommands() {
        return this.inner.listCommands ? this.inner.listCommands() : [];
    }
    async setModel(modelId) {
        if (this.inner.setModel) {
            await this.inner.setModel(modelId);
        }
    }
    async setThinkingOption(thinkingOptionId) {
        this.thinkingOptionId = thinkingOptionId ?? null;
        if (this.inner.setThinkingOption) {
            await this.inner.setThinkingOption(thinkingOptionId);
        }
    }
    async setFeature(featureId, value) {
        if (!this.inner.setFeature) {
            throw new Error("Agent session does not support setting features");
        }
        await this.inner.setFeature(featureId, value);
    }
}
export function wrapPiSession(session, config) {
    return new PiACPAgentSession(session, config);
}
export class PiACPAgentClient extends ACPAgentClient {
    constructor(options) {
        super({
            provider: "pi",
            logger: options.logger,
            runtimeSettings: options.runtimeSettings,
            defaultCommand: [process.execPath, resolvedPiAcpPath],
            defaultModes: [],
            modelTransformer: transformPiModels,
            sessionResponseTransformer: transformPiSessionResponse,
            toolSnapshotTransformer: transformPiToolSnapshot,
            thinkingOptionWriter: async (connection, sessionId, thinkingOptionId) => {
                await connection.setSessionMode({ sessionId, modeId: thinkingOptionId });
            },
            capabilities: PI_CAPABILITIES,
        });
    }
    async createSession(config, launchContext) {
        const session = await super.createSession(config, launchContext);
        return wrapPiSession(session, config);
    }
    async resumeSession(handle, overrides, launchContext) {
        const session = await super.resumeSession(handle, overrides, launchContext);
        return wrapPiSession(session, {
            provider: "pi",
            cwd: overrides?.cwd ?? process.cwd(),
            thinkingOptionId: overrides?.thinkingOptionId,
        });
    }
    async isAvailable() {
        if (!existsSync(resolvedPiAcpPath)) {
            return false;
        }
        if (!isCommandAvailable(process.env.PI_ACP_PI_COMMAND ?? "pi")) {
            return false;
        }
        return (Boolean(process.env.OPENAI_API_KEY) ||
            Boolean(process.env.ANTHROPIC_API_KEY) ||
            Boolean(process.env.OPENROUTER_API_KEY) ||
            existsSync(join(homedir(), ".pi", "agent", "auth.json")));
    }
}
//# sourceMappingURL=pi-acp-agent.js.map