<?php

namespace XZD\AI\V5\Agents;

use XZD\AI\V5\Core\Logger;

/**
 * 会话管理器 — AI 对话会话与消息的 CRUD
 *
 * 表: wp_xzd_ai_chat_sessions + wp_xzd_ai_chat_messages
 */
class SessionManager
{
    private string $sessionsTable;
    private string $messagesTable;

    public function __construct()
    {
        global $wpdb;
        $this->sessionsTable  = $wpdb->prefix . 'xzd_ai_chat_sessions';
        $this->messagesTable  = $wpdb->prefix . 'xzd_ai_chat_messages';
    }

    // ===== 会话 CRUD =====

    /**
     * 创建新会话
     */
    public function createSession(int $userId, string $title = '', string $model = '', string $provider = ''): array
    {
        global $wpdb;
        $sessionKey = $this->generateKey();

        $ok = $wpdb->insert($this->sessionsTable, [
            'session_key' => $sessionKey,
            'user_id'     => $userId,
            'title'       => $title ?: '新对话',
            'model'       => $model,
            'provider'    => $provider,
            'status'      => 'active',
            'created_at'  => current_time('mysql'),
            'updated_at'  => current_time('mysql'),
        ]);

        if (!$ok) {
            Logger::error('session_create', $wpdb->last_error);
            return ['success' => false, 'message' => '创建会话失败'];
        }

        $sessionId = (int) $wpdb->insert_id;

        Logger::info('session_create', $sessionKey, ['user_id' => $userId]);

        return [
            'success'     => true,
            'session_key' => $sessionKey,
            'id'          => $sessionId,
        ];
    }

    /**
     * 获取会话详情
     */
    public function getSession(string $sessionKey): ?array
    {
        global $wpdb;
        $row = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$this->sessionsTable} WHERE session_key = %s",
            $sessionKey
        ), ARRAY_A);

        return $row ?: null;
    }

    /**
     * 获取用户的所有会话（按更新时间倒序）
     */
    public function listSessions(int $userId, int $limit = 20, int $offset = 0): array
    {
        global $wpdb;
        return $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$this->sessionsTable} WHERE user_id = %d AND status != 'deleted' ORDER BY updated_at DESC LIMIT %d OFFSET %d",
            $userId, $limit, $offset
        ), ARRAY_A) ?: [];
    }

    /**
     * 更新会话
     */
    public function updateSession(string $sessionKey, array $data): bool
    {
        global $wpdb;
        $data['updated_at'] = current_time('mysql');
        return (bool) $wpdb->update($this->sessionsTable, $data, ['session_key' => $sessionKey]);
    }

    /**
     * 软删除会话
     */
    public function deleteSession(string $sessionKey): bool
    {
        return $this->updateSession($sessionKey, ['status' => 'deleted']);
    }

    /**
     * 更新会话摘要信息（标题/token/计数）
     */
    public function touchSession(string $sessionKey, array $meta): void
    {
        global $wpdb;
        $sets = [];
        $values = [];

        if (isset($meta['title'])) {
            $sets[] = 'title = %s';
            $values[] = $meta['title'];
        }
        if (isset($meta['model'])) {
            $sets[] = 'model = %s';
            $values[] = $meta['model'];
        }
        if (isset($meta['provider'])) {
            $sets[] = 'provider = %s';
            $values[] = $meta['provider'];
        }
        if (isset($meta['tokens'])) {
            $sets[] = 'total_tokens = total_tokens + %d';
            $values[] = $meta['tokens'];
        }
        if (isset($meta['cost'])) {
            $sets[] = 'total_cost = total_cost + %f';
            $values[] = $meta['cost'];
        }

        $sets[] = 'message_count = message_count + 1';
        $sets[] = 'updated_at = %s';
        $values[] = current_time('mysql');
        $values[] = $sessionKey;

        $wpdb->query($wpdb->prepare(
            "UPDATE {$this->sessionsTable} SET " . implode(', ', $sets) . " WHERE session_key = %s",
            $values
        ));
    }

    // ===== 消息 CRUD =====

    /**
     * 添加消息到会话
     */
    public function addMessage(string $sessionKey, string $role, string $content, array $meta = []): int
    {
        global $wpdb;

        $ok = $wpdb->insert($this->messagesTable, [
            'session_key'  => $sessionKey,
            'role'         => $role,
            'content'      => $content,
            'tool_calls'   => !empty($meta['tool_calls']) ? wp_json_encode($meta['tool_calls']) : null,
            'tool_call_id' => $meta['tool_call_id'] ?? null,
            'model'        => $meta['model'] ?? '',
            'input_tokens'  => $meta['input_tokens'] ?? 0,
            'output_tokens' => $meta['output_tokens'] ?? 0,
            'duration_ms'  => $meta['duration_ms'] ?? 0,
            'created_at'   => current_time('mysql'),
        ]);

        if (!$ok) {
            Logger::error('message_add', $wpdb->last_error);
            return 0;
        }

        return (int) $wpdb->insert_id;
    }

    /**
     * 获取会话的所有消息
     */
    public function getMessages(string $sessionKey, int $limit = 100): array
    {
        global $wpdb;
        return $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$this->messagesTable} WHERE session_key = %s ORDER BY id ASC LIMIT %d",
            $sessionKey, $limit
        ), ARRAY_A) ?: [];
    }

    /**
     * 获取最近 N 条消息（用于构建 LLM 上下文）
     */
    public function getRecentMessages(string $sessionKey, int $count = 20): array
    {
        global $wpdb;
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT id, role, content, tool_calls, tool_call_id FROM {$this->messagesTable}
             WHERE session_key = %s AND role != 'system'
             ORDER BY id DESC LIMIT %d",
            $sessionKey, $count
        ), ARRAY_A) ?: [];

        // 反转为时间正序
        $rows = array_reverse($rows);

        // 补全：如果第一条消息是 tool 角色，其 assistant(tool_calls) 可能被 LIMIT 截断
        if (!empty($rows) && $rows[0]['role'] === 'tool' && isset($rows[0]['id'])) {
            $firstId = (int) $rows[0]['id'];
            $prevRows = $wpdb->get_results($wpdb->prepare(
                "SELECT id, role, content, tool_calls, tool_call_id FROM {$this->messagesTable}
                 WHERE session_key = %s AND id < %d AND role = 'assistant' AND tool_calls IS NOT NULL
                 ORDER BY id DESC LIMIT 5",
                $sessionKey, $firstId
            ), ARRAY_A) ?: [];

            if (!empty($prevRows)) {
                $prevRows = array_reverse($prevRows);
                array_splice($rows, 0, 0, $prevRows);
            }
        }

        // 构造 LLM 消息格式
        $messages = [];
        foreach ($rows as $row) {
            $msg = ['role' => $row['role'], 'content' => $row['content']];
            if (!empty($row['tool_calls'])) {
                $msg['tool_calls'] = json_decode($row['tool_calls'], true);
            }
            if (!empty($row['tool_call_id'])) {
                $msg['tool_call_id'] = $row['tool_call_id'];
            }
            $messages[] = $msg;
        }

        // 完整性校验：截断可能导致 assistant(tool_calls) 缺少对应的 tool 消息
        // 遍历消息，移除无法配对的 tool_calls，避免 API 400 错误
        for ($i = 0; $i < count($messages); $i++) {
            if (!isset($messages[$i]['tool_calls']) || empty($messages[$i]['tool_calls'])) {
                continue;
            }
            $requiredIds = [];
            foreach ($messages[$i]['tool_calls'] as $tc) {
                if (!empty($tc['id'])) {
                    $requiredIds[$tc['id']] = true;
                }
            }
            // 统计后续 tool 消息中匹配的 tool_call_id
            for ($j = $i + 1; $j < count($messages); $j++) {
                if ($messages[$j]['role'] === 'tool' && isset($requiredIds[$messages[$j]['tool_call_id'] ?? ''])) {
                    unset($requiredIds[$messages[$j]['tool_call_id']]);
                }
                // 遇到下一个非 tool 消息时停止（tool 消息必须紧跟 assistant）
                if ($messages[$j]['role'] !== 'tool') break;
            }
            // 移除无法配对的 tool_calls
            if (!empty($requiredIds)) {
                $messages[$i]['tool_calls'] = array_values(array_filter(
                    $messages[$i]['tool_calls'],
                    fn($tc) => !isset($requiredIds[$tc['id'] ?? ''])
                ));
                if (empty($messages[$i]['tool_calls'])) {
                    unset($messages[$i]['tool_calls']);
                }
            }
        }

        // 反向校验：移除孤立的 tool 消息（没有匹配的前置 assistant(tool_calls)）
        // 这类孤儿的产生原因：assistant 消息被截断、DB写入中断、会话跨窗口残留
        foreach ($messages as $i => $msg) {
            if (($msg['role'] ?? '') !== 'tool' || empty($msg['tool_call_id'] ?? '')) {
                continue;
            }
            $hasMatchingAssistant = false;
            for ($j = $i - 1; $j >= 0; $j--) {
                if (($messages[$j]['role'] ?? '') !== 'assistant') continue;
                if (empty($messages[$j]['tool_calls'])) continue;
                foreach ($messages[$j]['tool_calls'] as $tc) {
                    if (($tc['id'] ?? '') === $msg['tool_call_id']) {
                        $hasMatchingAssistant = true;
                        break 2;
                    }
                }
                // tool 消息必须紧跟其 assistant(tool_calls)，遇到 assistant 没匹配到就不继续往回找了
                break;
            }
            if (!$hasMatchingAssistant) {
                unset($messages[$i]);
            }
        }
        $messages = array_values($messages);

        return $messages;
    }

    /**
     * 评价消息
     */
    public function rateMessage(int $messageId, int $rating): bool
    {
        global $wpdb;
        return (bool) $wpdb->update($this->messagesTable, ['rating' => $rating], ['id' => $messageId]);
    }

    // ===== 会话统计 =====

    /**
     * 获取用户会话统计
     */
    public function getUserStats(int $userId): array
    {
        global $wpdb;
        $total = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->sessionsTable} WHERE user_id = %d AND status = 'active'",
            $userId
        ));
        $totalMessages = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->messagesTable} m
             INNER JOIN {$this->sessionsTable} s ON m.session_key = s.session_key
             WHERE s.user_id = %d",
            $userId
        ));

        return [
            'total_sessions' => (int) $total,
            'total_messages' => (int) $totalMessages,
        ];
    }

    // ===== 内部 =====

    /**
     * 检查所需数据库表是否存在
     *
     * 兼容 MySQL 5.6 / 部分共享主机上 JSON 列类型不被支持导致建表失败的情况。
     * 表不存在时返回 false，调用方应向用户返回明确的配置引导信息。
     */
    public function hasTables(): bool
    {
        global $wpdb;
        return $wpdb->get_var("SHOW TABLES LIKE '{$this->sessionsTable}'") === $this->sessionsTable
            && $wpdb->get_var("SHOW TABLES LIKE '{$this->messagesTable}'") === $this->messagesTable;
    }

    private function generateKey(): string
    {
        return 'sk_' . bin2hex(random_bytes(16));
    }
}
