"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GolangProvider = void 0;
const child_process_1 = require("child_process");
const fs_1 = __importDefault(require("fs"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const util_1 = __importDefault(require("util"));
const cache_1 = require("../cache");
const logger_1 = __importDefault(require("../logger"));
const util_2 = require("../util");
const createHash_1 = require("../util/createHash");
const json_1 = require("../util/json");
const execAsync = util_1.default.promisify(child_process_1.exec);
class GolangProvider {
    constructor(runPath, options) {
        this.options = options;
        const { filePath: providerPath, functionName } = (0, util_2.parsePathOrGlob)(options?.config.basePath || '', runPath);
        this.scriptPath = path_1.default.relative(options?.config.basePath || '', providerPath);
        this.functionName = functionName || null;
        this.id = () => options?.id ?? `golang:${this.scriptPath}:${this.functionName || 'default'}`;
        this.label = options?.label;
        this.config = options?.config ?? {};
    }
    id() {
        return `golang:${this.scriptPath}:${this.functionName || 'default'}`;
    }
    async executeGolangScript(prompt, context, apiType) {
        const absPath = path_1.default.resolve(path_1.default.join(this.options?.config.basePath || '', this.scriptPath));
        logger_1.default.debug(`Computing file hash for script ${absPath}`);
        const fileHash = (0, createHash_1.sha256)(fs_1.default.readFileSync(absPath, 'utf-8'));
        const cacheKey = `golang:${this.scriptPath}:${apiType}:${fileHash}:${prompt}:${JSON.stringify(this.options)}:${JSON.stringify(context?.vars)}`;
        const cache = await (0, cache_1.getCache)();
        let cachedResult;
        if ((0, cache_1.isCacheEnabled)()) {
            cachedResult = (await cache.get(cacheKey));
        }
        if (cachedResult) {
            logger_1.default.debug(`Returning cached ${apiType} result for script ${absPath}`);
            return JSON.parse(cachedResult);
        }
        else {
            if (context) {
                // These are not useful in Golang
                delete context.fetchWithCache;
                delete context.getCache;
                delete context.logger;
            }
            const args = apiType === 'call_api' ? [prompt, this.options, context] : [prompt, this.options];
            logger_1.default.debug(`Running Golang script ${absPath} with scriptPath ${this.scriptPath} and args: ${(0, json_1.safeJsonStringify)(args)}`);
            const functionName = this.functionName || apiType;
            let tempDir;
            try {
                tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'golang-provider-'));
                const tempWrapperPath = path_1.default.join(tempDir, 'wrapper.go');
                const tempScriptPath = path_1.default.join(tempDir, 'provider.go');
                const executablePath = path_1.default.join(tempDir, 'golang_wrapper');
                fs_1.default.copyFileSync(path_1.default.join(__dirname, '../golang/wrapper.go'), tempWrapperPath);
                fs_1.default.copyFileSync(absPath, tempScriptPath);
                if (!fs_1.default.existsSync(executablePath)) {
                    // Compile the Go code only if the executable doesn't exist
                    const compileCommand = `${this.config.goExecutable || 'go'} build -o ${executablePath} ${tempWrapperPath} ${tempScriptPath}`;
                    await execAsync(compileCommand);
                }
                // Run the compiled binary
                const command = `${executablePath} ${tempScriptPath} ${functionName} '${(0, json_1.safeJsonStringify)(args)}'`;
                logger_1.default.debug(`Running command: ${command}`);
                const { stdout, stderr } = await execAsync(command);
                if (stderr) {
                    logger_1.default.error(`Golang script stderr: ${stderr}`);
                }
                logger_1.default.debug(`Golang script stdout: ${stdout}`);
                const result = JSON.parse(stdout);
                if ((0, cache_1.isCacheEnabled)() && !('error' in result)) {
                    await cache.set(cacheKey, JSON.stringify(result));
                }
                return result;
            }
            catch (error) {
                logger_1.default.error(`Error running Golang script: ${error.message}`);
                logger_1.default.error(`Full error object: ${JSON.stringify(error)}`);
                throw new Error(`Error running Golang script: ${error.message}`);
            }
            finally {
                // Clean up temporary directory
                if (tempDir) {
                    fs_1.default.rmSync(tempDir, { recursive: true, force: true });
                }
            }
        }
    }
    async callApi(prompt, context) {
        return this.executeGolangScript(prompt, context, 'call_api');
    }
    async callEmbeddingApi(prompt) {
        return this.executeGolangScript(prompt, undefined, 'call_embedding_api');
    }
    async callClassificationApi(prompt) {
        return this.executeGolangScript(prompt, undefined, 'call_classification_api');
    }
}
exports.GolangProvider = GolangProvider;
//# sourceMappingURL=golangCompletion.js.map