<?php

namespace XZD\AI\V5\AI;

/**
 * SSE 流式引擎 — 管理流式连接生命周期
 *
 * 职责:
 * - 从 Provider 获取流式 Generator
 * - 写入 Redis Streams 或 MySQL 降级存储
 * - 管理断线重连所需的 cursor/stream_id
 */
class StreamEngine
{
    private string $streamId;
    private int $chunkIndex = 0;

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

    /**
     * 执行流式生成，将 chunk 写入存储
     *
     * @param ProviderInterface $provider
     * @param array $messages
     * @param array $options
     * @return array 最终结果 ['stream_id','total_chunks','content','tool_calls','input_tokens','output_tokens']
     */
    public function run(ProviderInterface $provider, array $messages, array $options = []): array
    {
        $fullContent = '';
        $toolCalls = null;
        $totalChunks = 0;

        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'];
            }

            $this->storeChunk($chunk);

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

        $this->storeComplete();

        return [
            'stream_id'    => $this->streamId,
            'total_chunks' => $totalChunks,
            'content'      => $fullContent,
            'tool_calls'   => $toolCalls,
            'done'         => true,
        ];
    }

    /**
     * 获取从指定 cursor 开始的 chunk（断线重连用）
     */
    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 ?: [];
    }

    /**
     * 清理过期的 stream 数据
     */
    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'),
        ]);
    }
}
