<?php

namespace Autopilot\Controller;

use App\Controller\App;


class Autopilot extends App {

    public function image() {

        $this->helper('session')->close();
        $this->hasValidCsrfToken(true);

        $prompt = $this->param('prompt');
        $size = $this->param('size');
        $style = $this->param('style', 'natural');

        if (!$prompt || !$size) {
            return false;
        }

        if (\function_exists('ini_set')) {
            \ini_set('max_execution_time', 600);
            \ini_set('output_buffering', 'Off');
        }

        \header('Content-Type: text/plain');
        \header('Cache-Control: no-cache');
        \header('Connection: keep-alive');

        $response = $this->module('autopilot')->client()->images()->create([
            'model' => $this->app->retrieve('autopilot/openAI/imageModel', 'dall-e-3'),
            'prompt' => $prompt,
            'n' => 1,
            'style' => $style,
            'size' => $size,
            'response_format' => 'url',
        ]);

        return ['url' => $response->toArray()['data'][0]['url'] ?? null];
    }

    public function chat() {

        $this->helper('session')->close();
        $this->hasValidCsrfToken(true);

        $messages = $this->param('messages', []);
        $uid = $this->param('uid');
        $useTools = $this->param('useTools', true);

        if (!$this->app->retrieve('autopilot/useTools', true)) {
            $useTools = false;
        }

        if (!\is_array($messages) || !\count($messages)) {
            return false;
        }

        if (\ob_get_level()) \ob_end_clean();

        if (\function_exists('ini_set')) {
            \ini_set('max_execution_time', 600);
            \ini_set('output_buffering', 'Off');
        }

        \header('Content-Type: text/plain');
        \header('Cache-Control: no-cache');
        \header('Connection: keep-alive');

        try {
            // Get agent and available tools
            $agent = $this->helper('autopilot:agent');
            $tools = $useTools ? $agent->getToolDefinitions() : [];

            // Add system message if tools are available and not already present
            if (!empty($tools) && (!isset($messages[0]['role']) || $messages[0]['role'] !== 'system')) {
                \array_unshift($messages, [
                    'role' => 'system',
                    'content' => 'You are a helpful assistant for Cockpit CMS. You have access to tools that allow you to interact with the CMS data. Use these tools to answer questions about collections, entries, and system information. If the user asks what you can do or needs help, use the getCockpitHelp tool to show available options.'
                ]);
            }

            // Prepare chat parameters
            $chatParams = [
                'model' => $this->module('autopilot')->chatModel(),
                'messages' => $messages,
            ];

            // Add tools if available
            if (!empty($tools)) {
                $chatParams['tools'] = $tools;
                $chatParams['tool_choice'] = 'auto';
            }

            $stream = $this->module('autopilot')->client()->chat()->createStreamed($chatParams);
        } catch (\Exception $e) {
            echo "Error initializing chat: " . $e->getMessage() . "\n";
            echo "Stack trace: " . $e->getTraceAsString() . "\n";
            return '';
        }

        $content = '';
        $chunk = 0;
        $toolCalls = [];
        $currentToolCall = null;

        \ob_start();

        try {

            $responseCount = 0;

            foreach ($stream as $response) {

                $responseCount++;
                $chunk += 1;

                // Handle regular content
                if (isset($response->choices[0]->delta->content)) {
                    $text = $response->choices[0]->delta->content;
                    $content .= $text;
                    echo $text;
                }

                // Handle tool calls (use camelCase property name)
                if (isset($response->choices[0]->delta->toolCalls) && !empty($response->choices[0]->delta->toolCalls)) {
                    foreach ($response->choices[0]->delta->toolCalls as $toolCallDelta) {

                        // New tool call
                        if (isset($toolCallDelta->id)) {
                            if ($currentToolCall) {
                                $toolCalls[] = $currentToolCall;
                            }
                            $currentToolCall = [
                                'id' => $toolCallDelta->id,
                                'type' => $toolCallDelta->type ?? 'function',
                                'function' => [
                                    'name' => $toolCallDelta->function->name ?? '',
                                    'arguments' => ''
                                ]
                            ];
                        }

                        // Accumulate arguments
                        if ($currentToolCall && isset($toolCallDelta->function->arguments)) {
                            $currentToolCall['function']['arguments'] .= $toolCallDelta->function->arguments;
                        }
                    }
                }

                // Check if we're at the end and have a pending tool call (use camelCase)
                if (isset($response->choices[0]->finishReason)) {
                    if ($response->choices[0]->finishReason === 'tool_calls') {
                        if ($currentToolCall) {
                            $toolCalls[] = $currentToolCall;
                            $currentToolCall = null;
                        }
                    }
                }

                // Flush more frequently for debugging
                if ($chunk >= 5) {
                    if ($uid) {
                        $this->app->memory->set($uid, $content);
                    }
                    $chunk = 0;
                    \ob_flush();
                    \flush();
                }
            }
            // Flush any remaining content
            \ob_flush();
            \flush();

        } catch (\Exception $e) {
            echo "\n\nError during streaming: " . $e->getMessage() . "\n";
            \ob_flush();
            \flush();
        }

        // Process any tool calls
        if (!empty($toolCalls)) {

            // Clear the agent's execution tracking for this conversation
            $agent->clearExecutions();

            // First, add the assistant's message with tool_calls to the conversation
            $assistantMessage = [
                'role' => 'assistant',
                'content' => $content ?: null,
            ];

            // Add tool_calls to the assistant message
            if (!empty($toolCalls)) {
                $assistantMessage['tool_calls'] = $toolCalls;
            }

            $messages[] = $assistantMessage;

            // Execute tools and get results
            $toolResults = $agent->processToolCalls($toolCalls);

            // Add tool results to messages
            foreach ($toolResults as $result) {
                $messages[] = $result;
            }

            // Continue the conversation with tool results (silently)

            // Make another request with the tool results
            $followUpParams = [
                'model' => $this->module('autopilot')->chatModel(),
                'messages' => $messages,
            ];

            if (!empty($tools)) {
                $followUpParams['tools'] = $tools;
                $followUpParams['tool_choice'] = 'auto';
            }

            $followUpStream = $this->module('autopilot')->client()->chat()->createStreamed($followUpParams);

            foreach ($followUpStream as $response) {
                if (isset($response->choices[0]->delta->content)) {
                    $text = $response->choices[0]->delta->content;
                    $content .= $text;
                    echo $text;
                }

                $chunk += 1;
                if ($chunk >= 50) {
                    if ($uid) {
                        $this->app->memory->set($uid, $content);
                    }
                    $chunk = 0;
                    \ob_flush();
                    \flush();
                }
            }
        }

        if ($uid) {
            $this->app->memory->del($uid);
        }

        return '';
    }

    public function progress($uid = null) {

        $this->helper('session')->close();
        $this->hasValidCsrfToken(true);

        $uid = $this->param('uid', $uid);

        if (!$uid) {
            return false;
        }

        return ['content' => $this->app->memory->get($uid)];
    }

    public function imageToAsset() {

        $this->helper('session')->close();
        $this->hasValidCsrfToken(true);

        $url = $this->param('url');

        if (!$url) {
            return false;
        }

        $ext = \strtolower(\pathinfo(\parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION));
        $tmp = $this->app->path('#tmp:').'/'.\uniqid().".{$ext}";

        // Fetch the file from the external server
        $contents = @\file_get_contents($url);

        if ($contents !== false) {

            $saveFile = \file_put_contents($tmp, $contents);

            if ($saveFile !== false) {

                $meta = ['folder' => $this->param('folder', '')];

                $param = [
                    'name' => ["Autopilot-image.{$ext}"],
                    'full_path' => ["Autopilot-image.{$ext}"],
                    'type' => ["image/{$ext}"],
                    'tmp_name' => [$tmp],
                    'error' => [0],
                    'size' => [\filesize($tmp)],
                ];

                return [
                    'asset' => $this->module('assets')->upload($param, $meta, false)['assets'][0] ?? null,
                ];
            }
        }

        throw new \Exception('Failed to import generated image.');
    }

}
