<?php

namespace XZD\AI\V5\AI;

/**
 * SSE streaming engine
 */
class StreamEngine
{
    private string $streamId;
    private int $chunkIndex = 0;

    public function __construct(string $streamId)
    {
        $this->streamId = $streamId;
    }

    /**
     * Execute streaming generation
     *
     * @param ProviderInterface $provider
     * @param array $messages
     * @param array $options
     * @return array Result with stream_id, total_chunks, content, tool_calls, tokens
     */
    public function run(ProviderInterface $provider, array $messages, array $options = []): array
    {
        $fullContent = '';
        $toolCalls = null;
        $totalChunks = 0;
        $finalUsage = null;

        foreach ($provider->chatStream($messages, $options) as $chunk) {
            if (isset($chunk['error'])) {
                $this->storeError($chunk['error']);
                return [
                    'stream_id'    => $this->streamId,
                    'total_chunks' => $totalChunks,
                    'content'      => $fullContent,
                    'tool_calls'   => $toolCalls,
                    'error'        => $chunk['error'],
                ];
            }

            $delta = $chunk['delta'] ?? '';
            $fullContent .= $delta;
            $totalChunks++;

            if (!empty($chunk['tool_call'])) {
                $toolCalls = $chunk['tool_call'];
            }

            if (!empty($chunk['usage'])) {
                $finalUsage = $chunk['usage'];
            }

            $this->storeChunk($chunk);

            if ($chunk['done'] ?? false) {
                break;
            }
        }

        $this->storeComplete();

        if ($finalUsage) {
            $this->trackStreamCost($provider, $finalUsage);
        }

        return [
            'stream_id'     => $this->streamId,
            'total_chunks'  => $totalChunks,
            'content'       => $fullContent,
            'tool_calls'    => $toolCalls,
            'done'          => true,
            'input_tokens'  => $finalUsage['prompt_tokens'] ?? 0,
            'output_tokens' => $finalUsage['completion_tokens'] ?? 0,
            'cache_tokens'  => $finalUsage['prompt_cache_hit_tokens']
                            ?? $finalUsage['prompt_tokens_details']['cached_tokens']
                            ?? $finalUsage['cache_tokens']
                            ?? 0,
        ];
    }

    /**
     * Record streaming call cost
     */
    private function trackStreamCost(ProviderInterface $provider, array $usage): void
    {
        try {
            if (!class_exists(\XZD\AI\V5\Analytics\CostTracker::class)) return;

            $inputTokens = $usage['prompt_tokens'] ?? 0;
            $outputTokens = $usage['completion_tokens'] ?? 0;
            $cacheTokens = $usage['prompt_cache_hit_tokens']
                        ?? $usage['prompt_tokens_details']['cached_tokens']
                        ?? $usage['cache_tokens']
                        ?? 0;
            $model = $provider->getConfig()['model'] ?? 'unknown';

            \XZD\AI\V5\Analytics\CostTracker::recordStreamCall(
                $model, $inputTokens, $outputTokens, $cacheTokens, $this->streamId
            );
        } catch (\Throwable $e) {
            error_log("[XZD-AI] StreamEngine cost tracking failed: {$e->getMessage()}");
        }
    }

    /**
     * Get chunks from cursor position
     *
     * @param int $cursor
     * @return array
     */
    public function getFromChunk(int $cursor): array
    {
        global $wpdb;
        $table = $wpdb->prefix . 'xzd_ai_chat_stream_chunks';

        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT chunk_index, content, tool_call_chunk FROM {$table} WHERE stream_id = %s AND chunk_index >= %d ORDER BY chunk_index ASC",
            $this->streamId, $cursor
        ), ARRAY_A);

        return $rows ?: [];
    }

    /**
     * Clean expired stream data
     *
     * @param int $olderThanSeconds
     * @return int
     */
    public static function cleanExpired(int $olderThanSeconds = 3600): int
    {
        global $wpdb;
        $table = $wpdb->prefix . 'xzd_ai_chat_stream_chunks';
        $cutoff = date('Y-m-d H:i:s', time() - $olderThanSeconds);

        return (int) $wpdb->query($wpdb->prepare(
            "DELETE FROM {$table} WHERE created_at < %s", $cutoff
        ));
    }

    private function storeChunk(array $chunk): void
    {
        global $wpdb;
        $table = $wpdb->prefix . 'xzd_ai_chat_stream_chunks';

        $wpdb->insert($table, [
            'stream_id'       => $this->streamId,
            'chunk_index'     => $this->chunkIndex,
            'content'         => $chunk['delta'] ?? '',
            'tool_call_chunk' => !empty($chunk['tool_call']) ? wp_json_encode($chunk['tool_call']) : null,
            'created_at'      => current_time('mysql'),
        ]);

        $this->chunkIndex++;
    }

    private function storeComplete(): void
    {
        global $wpdb;
        $table = $wpdb->prefix . 'xzd_ai_chat_stream_chunks';

        $wpdb->insert($table, [
            'stream_id'   => $this->streamId,
            'chunk_index' => $this->chunkIndex,
            'content'     => '[DONE]',
            'created_at'  => current_time('mysql'),
        ]);
    }

    private function storeError(string $error): void
    {
        global $wpdb;
        $table = $wpdb->prefix . 'xzd_ai_chat_stream_chunks';

        $wpdb->insert($table, [
            'stream_id'   => $this->streamId,
            'chunk_index' => $this->chunkIndex,
            'content'     => '[ERROR] ' . $error,
            'created_at'  => current_time('mysql'),
        ]);
    }
}
