<?php
/**
 * OpenAI Provider
 *
 * Implementation of AIProviderInterface for OpenAI.
 * Migrated from integrations/openai/Integration.php
 *
 * @package FleekDash\AI\Providers\OpenAI
 * @since 2.3.0
 */

namespace FleekDash\AI\Providers\OpenAI;

use FleekDash\AI\Core\AIProviderInterface;
use FleekDash\AI\Providers\AbstractProvider;
use Throwable;

defined('ABSPATH') || exit;

require_once __DIR__ . '/OpenAIProviderException.php';

/**
 * Class OpenAIProvider
 *
 * OpenAI AI provider implementation.
 */
class OpenAIProvider extends AbstractProvider implements AIProviderInterface
{
    /**
     * OpenAI client instance
     *
     * @var OpenAIClient|null
     */
    private ?OpenAIClient $client = null;

    /**
     * Get provider unique identifier
     *
     * @return string
     */
    public function getId(): string
    {
        return 'openai';
    }

    /**
     * Get provider display name
     *
     * @return string
     */
    public function getName(): string
    {
        return 'OpenAI';
    }

    /**
     * Get provider icon name
     *
     * @return string
     */
    public function getIcon(): string
    {
        return 'sparkles';
    }

    /**
     * Get provider description
     *
     * @return string
     */
    public function getDescription(): string
    {
        return 'Integrate OpenAI\'s powerful AI models (GPT-4, GPT-3.5) into your FleekDash installation.';
    }

    /**
     * Get OpenAI client instance
     *
     * @return OpenAIClient
     */
    private function getClient(): OpenAIClient
    {
        if ($this->client === null) {
            $this->client = new OpenAIClient($this->getSettings());
        }

        return $this->client;
    }

    /**
     * Send chat completion request
     *
     * @param array $messages Array of message objects
     * @param array $options Additional options
     * @return array Response array
     * @throws OpenAIProviderException If provider is not configured
     */
    public function chat(array $messages, array $options = []): array
    {
        $settings = $this->getSettings();

        if (empty($settings['api_key'])) {
            throw new OpenAIProviderException('OpenAI API key is not configured');
        }

        $params = [
            'messages' => $messages,
            'model' => $options['model'] ?? $settings['model'] ?? 'gpt-4o',
            'temperature' => $options['temperature'] ?? $settings['temperature'] ?? 0.9,
            'max_tokens' => $options['max_tokens'] ?? $settings['max_tokens'] ?? 4000,
        ];

        $response = $this->getClient()->chat($params, false);

        // Format response to match interface contract
        return [
            'content' => $response['choices'][0]['message']['content'] ?? '',
            'model' => $response['model'] ?? $params['model'],
            'usage' => $response['usage'] ?? [],
            'finish_reason' => $response['choices'][0]['finish_reason'] ?? 'stop',
        ];
    }

    /**
     * Stream chat completion
     *
     * @param array $messages Array of message objects
     * @param callable $callback Callback function for each chunk
     * @param array $options Additional options
     * @return void
     * @throws OpenAIProviderException If input is invalid or provider is not configured
     */
    public function streamChat(array $messages, callable $callback, array $options = []): void
    {
        \assert(is_callable($callback));

        // Validate messages before proceeding
        if (empty($messages) || !is_array($messages)) {
            throw new OpenAIProviderException('Messages parameter is required and must be a non-empty array');
        }

        $settings = $this->getSettings();

        error_log('[OpenAIProvider::streamChat] api_key_length=' . strlen($settings['api_key'] ?? '') . ', model=' . ($options['model'] ?? $settings['model'] ?? 'gpt-4o'));

        if (empty($settings['api_key'])) {
            throw new OpenAIProviderException('OpenAI API key is not configured');
        }

        error_log('[OpenAIProvider::streamChat] Starting stream with model: ' . ($options['model'] ?? $settings['model'] ?? 'gpt-4o'));

        // Set up streaming headers
        OpenAIStream::setupStreamingHeaders();

        $params = [
            'messages' => $messages,
            'model' => $options['model'] ?? $settings['model'] ?? 'gpt-4o',
            'temperature' => $options['temperature'] ?? $settings['temperature'] ?? 0.9,
            'max_tokens' => $options['max_tokens'] ?? $settings['max_tokens'] ?? 4000,
        ];

        // OpenAIStream handles HTTP output directly via sendTextChunk/sendCompletionSignal
        $this->getClient()->chat($params, true);
    }

    /**
     * Get available models
     *
     * @return array
     */
    public function getModels(): array
    {
        return [
            'gpt-4o' => 'GPT-4o',
            'gpt-4-turbo' => 'GPT-4 Turbo',
            'gpt-4' => 'GPT-4',
            'gpt-3.5-turbo' => 'GPT-3.5 Turbo',
        ];
    }

    /**
     * Validate API key format
     *
     * @param string $key API key
     * @return bool
     */
    public function validateApiKey(string $key): bool
    {
        return !empty($key) && strpos($key, 'sk-') === 0;
    }

    /**
     * Test API key by making a simple request
     *
     * @param string $key API key to test
     * @return array ['valid' => bool, 'error' => string|null]
     */
    public function testApiKey(string $key): array
    {
        if (!$this->validateApiKey($key)) {
            return [
                'valid' => false,
                'error' => 'Invalid API key format. OpenAI keys should start with "sk-"',
            ];
        }

        try {
            // Make a minimal test request
            $testClient = new OpenAIClient(['api_key' => $key]);
            $testClient->chat([
                'messages' => [
                    ['role' => 'user', 'content' => 'test']
                ],
                'model' => 'gpt-3.5-turbo',
                'max_tokens' => 5,
            ], false);

            return [
                'valid' => true,
                'error' => null,
            ];
        } catch (Throwable $e) {
            return [
                'valid' => false,
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * Get default settings schema
     *
     * @return array
     */
    public function getSettingsSchema(): array
    {
        return [
            'api_key' => [
                'type' => 'password',
                'label' => 'API Key',
                'description' => 'Your OpenAI API key (starts with sk-)',
                'required' => true,
            ],
            'model' => [
                'type' => 'select',
                'label' => 'Model',
                'description' => 'The OpenAI model to use',
                'options' => $this->getModels(),
                'default' => 'gpt-4o',
            ],
            'temperature' => [
                'type' => 'number',
                'label' => 'Temperature',
                'description' => 'Controls randomness: 0 is focused, 1 is more creative',
                'min' => 0,
                'max' => 2,
                'step' => 0.1,
                'default' => 0.9,
            ],
            'max_tokens' => [
                'type' => 'number',
                'label' => 'Max Tokens',
                'description' => 'Maximum number of tokens to generate',
                'min' => 1,
                'max' => 4096,
                'default' => 4000,
            ],
        ];
    }

    /**
     * Get default settings values
     *
     * @return array
     */
    public function getDefaultSettings(): array
    {
        return [
            'api_key' => '',
            'model' => 'gpt-4o',
            'temperature' => 0.9,
            'max_tokens' => 4000,
        ];
    }

    /**
     * Override settings key to maintain backward compatibility
     *
     * @return string
     */
    protected function getSettingsKey(): string
    {
        // Use old option key for backward compatibility
        return 'fleekdash_openai_settings';
    }
}
