import { createLLM, toOAITools, LLMMessage } from './llm';
import { AgentConfig } from './agents';
import { executeTool, ToolContext } from './tools';
import { resolvePrompt } from './prompts/loader';
import { Job, updateJob } from './job-store';

const MAX_TURNS = 40;

export interface RunResult {
    finalText: string;
    toolCallCount: number;
    turns: number;
    model: string;
}

/**
 * Core agent execution loop — model-agnostic via the unified LLM client.
 *
 * Agents use their configured model tier (A/B/C) or a specific model ID.
 * Tool calling uses OpenAI format throughout.
 */
export async function runAgent(
    job: Job,
    config: AgentConfig,
    task: string,
    ctx: ToolContext
): Promise<RunResult> {
    const llm = createLLM(config.model, { temperature: 0.2 });
    const oaiTools = toOAITools(config.tools);

    const history: LLMMessage[] = [
        { role: 'user', content: task }
    ];

    let toolCallCount = 0;
    let turn = 0;
    let finalText = '';

    updateJob(job.id, { status: 'running', progress: `Starting ${config.name} (${llm.modelId})…` });

    while (turn < MAX_TURNS) {
        turn++;

        const systemPrompt = resolvePrompt(config.promptId);
        const messages: LLMMessage[] = [
            { role: 'system', content: systemPrompt },
            ...history
        ];

        const response = await llm.chat(messages, oaiTools, 8192);

        // Build assistant message for history
        const assistantMsg: LLMMessage = {
            role: 'assistant',
            content: response.content,
            tool_calls: response.tool_calls.length > 0 ? response.tool_calls : undefined
        };
        history.push(assistantMsg);

        // No tool calls — agent is done
        if (response.tool_calls.length === 0) {
            finalText = response.content ?? '';
            break;
        }

        // Execute tool calls
        for (const tc of response.tool_calls) {
            const fnName = tc.function.name;
            let fnArgs: Record<string, unknown> = {};
            try { fnArgs = JSON.parse(tc.function.arguments || '{}'); } catch { /* bad JSON */ }

            toolCallCount++;
            updateJob(job.id, {
                progress: `Turn ${turn}: calling ${fnName}…`,
                toolCalls: [...(job.toolCalls || []), {
                    turn,
                    tool: fnName,
                    args: fnArgs,
                    timestamp: new Date().toISOString()
                }]
            });

            let result: unknown;
            try {
                result = await executeTool(fnName, fnArgs, ctx);
            } catch (err) {
                result = { error: err instanceof Error ? err.message : String(err) };
            }

            history.push({
                role: 'tool',
                tool_call_id: tc.id,
                name: fnName,
                content: typeof result === 'string' ? result : JSON.stringify(result)
            });
        }
    }

    if (turn >= MAX_TURNS && !finalText) {
        finalText = `Agent hit the ${MAX_TURNS}-turn safety limit. Tool calls made: ${toolCallCount}.`;
    }

    return { finalText, toolCallCount, turns: turn, model: llm.modelId };
}
