<?php

namespace HaoZiTeam\AIPost\Service\Features;

use WP_REST_Request;
use WP_REST_Response;

defined('ABSPATH') || exit;

class AdminChatEndpoint
{
    public static function register(): void
    {
        add_action('rest_api_init', [__CLASS__, 'register_routes']);
    }

    public static function register_routes(): void
    {
        register_rest_route('aipost/v1', '/chat/models', [
            'methods' => 'GET',
            'callback' => [__CLASS__, 'handle_models'],
            'permission_callback' => [__CLASS__, 'permission_check'],
        ]);

        register_rest_route('aipost/v1', '/chat/sessions', [
            'methods' => 'GET',
            'callback' => [__CLASS__, 'handle_sessions_list'],
            'permission_callback' => [__CLASS__, 'permission_check'],
            'args' => [
                'keyword' => [ 'required' => false, 'type' => 'string' ],
                'page' => [ 'required' => false, 'type' => 'integer' ],
                'page_size' => [ 'required' => false, 'type' => 'integer' ],
            ],
        ]);

        register_rest_route('aipost/v1', '/chat/sessions', [
            'methods' => 'POST',
            'callback' => [__CLASS__, 'handle_session_create'],
            'permission_callback' => [__CLASS__, 'permission_check'],
            'args' => [
                'title' => [ 'required' => false, 'type' => 'string' ],
                'model' => [ 'required' => false, 'type' => 'string' ],
            ],
        ]);

        register_rest_route('aipost/v1', '/chat/sessions/(?P<id>\d+)', [
            'methods' => 'PATCH',
            'callback' => [__CLASS__, 'handle_session_rename'],
            'permission_callback' => [__CLASS__, 'permission_check'],
            'args' => [
                'title' => [ 'required' => true, 'type' => 'string' ],
            ],
        ]);

        register_rest_route('aipost/v1', '/chat/sessions/(?P<id>\d+)', [
            'methods' => 'DELETE',
            'callback' => [__CLASS__, 'handle_session_delete'],
            'permission_callback' => [__CLASS__, 'permission_check'],
        ]);

        register_rest_route('aipost/v1', '/chat/sessions/(?P<id>\d+)/messages', [
            'methods' => 'GET',
            'callback' => [__CLASS__, 'handle_messages_list'],
            'permission_callback' => [__CLASS__, 'permission_check'],
            'args' => [
                'before_id' => [ 'required' => false, 'type' => 'integer' ],
                'limit' => [ 'required' => false, 'type' => 'integer' ],
            ],
        ]);

        register_rest_route('aipost/v1', '/chat/sessions/(?P<id>\d+)/messages', [
            'methods' => 'POST',
            'callback' => [__CLASS__, 'handle_message_send'],
            'permission_callback' => [__CLASS__, 'permission_check'],
            'args' => [
                'content' => [ 'required' => true, 'type' => 'string' ],
                'model' => [ 'required' => false, 'type' => 'string' ],
            ],
        ]);
    }

    public static function permission_check(): bool
    {
        return is_user_logged_in() && current_user_can('manage_options');
    }

    public static function handle_models(WP_REST_Request $req)
    {
        try {
            $models = EditorGenerateUI::build_model_options();
        } catch (\Throwable $e) {
            $models = [
                'provider' => 'multi',
                'default' => '',
                'options' => [],
                'allow' => [],
                'enabled_providers' => [],
            ];
        }

        return new WP_REST_Response([
            'ok' => true,
            'models' => $models,
        ]);
    }

    private static function parse_model_value(string $val): array
    {
        $val = trim((string)$val);
        $provider = '';
        $model = '';

        if ($val === '') {
            return [ 'provider' => '', 'model' => '' ];
        }

        if (strpos($val, '::') !== false) {
            $parts = explode('::', $val, 2);
            $provider = trim((string)($parts[0] ?? ''));
            $model = trim((string)($parts[1] ?? ''));
        } else {
            $model = $val;
        }

        return [
            'provider' => $provider,
            'model' => $model,
        ];
    }

    private static function get_session_row(int $session_id): ?array
    {
        global $wpdb;

        $sessions = AdminChatTables::table_sessions();
        $uid = (int) get_current_user_id();

        $row = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$sessions} WHERE id=%d AND user_id=%d AND deleted_at IS NULL",
                $session_id,
                $uid
            ),
            ARRAY_A
        );

        return is_array($row) ? $row : null;
    }

    public static function handle_sessions_list(WP_REST_Request $req)
    {
        global $wpdb;

        $sessions = AdminChatTables::table_sessions();
        $messages = AdminChatTables::table_messages();

        $uid = (int) get_current_user_id();
        $keyword = trim((string)$req->get_param('keyword'));
        $page = (int) ($req->get_param('page') ?: 1);
        $page_size = (int) ($req->get_param('page_size') ?: 20);

        if ($page < 1) {
            $page = 1;
        }
        if ($page_size < 1) {
            $page_size = 20;
        }
        if ($page_size > 100) {
            $page_size = 100;
        }

        $whereSql = "user_id=%d AND deleted_at IS NULL";
        $whereArgs = [ $uid ];

        if ($keyword !== '') {
            $whereSql .= " AND title LIKE %s";
            $whereArgs[] = '%' . $wpdb->esc_like($keyword) . '%';
        }

        $count = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$sessions} WHERE {$whereSql}",
            $whereArgs
        ));

        $offset = ($page - 1) * $page_size;

        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT id, title, model_key, model_name, created_at, updated_at FROM {$sessions} WHERE {$whereSql} ORDER BY updated_at DESC LIMIT %d OFFSET %d",
            array_merge($whereArgs, [ $page_size, $offset ])
        ), ARRAY_A);

        $rows = is_array($rows) ? $rows : [];
        $sessionIds = [];
        foreach ($rows as $r) {
            $sessionIds[] = (int) ($r['id'] ?? 0);
        }

        $lastBySession = [];
        if (!empty($sessionIds)) {
            $in = implode(',', array_map('intval', $sessionIds));
            // 取每个 session 最新消息（按 id 最大）
            $lastRows = $wpdb->get_results(
                "SELECT m.session_id, m.content FROM {$messages} m
                 INNER JOIN (
                    SELECT session_id, MAX(id) AS max_id FROM {$messages}
                    WHERE session_id IN ({$in})
                    GROUP BY session_id
                 ) t ON t.session_id=m.session_id AND t.max_id=m.id",
                ARRAY_A
            );
            if (is_array($lastRows)) {
                foreach ($lastRows as $lr) {
                    $sid = (int)($lr['session_id'] ?? 0);
                    $c = (string)($lr['content'] ?? '');
                    $c = wp_strip_all_tags($c);
                    if (function_exists('mb_substr')) {
                        $c = (string) mb_substr($c, 0, 80, 'UTF-8');
                    } else {
                        $c = substr($c, 0, 80);
                    }
                    $lastBySession[$sid] = $c;
                }
            }
        }

        $out = [];
        foreach ($rows as $r) {
            $sid = (int) ($r['id'] ?? 0);
            $out[] = [
                'id' => $sid,
                'title' => (string)($r['title'] ?? ''),
                'model_key' => (string)($r['model_key'] ?? ''),
                'model_name' => (string)($r['model_name'] ?? ''),
                'created_at' => (string)($r['created_at'] ?? ''),
                'updated_at' => (string)($r['updated_at'] ?? ''),
                'last_message_excerpt' => (string)($lastBySession[$sid] ?? ''),
            ];
        }

        return new WP_REST_Response([
            'ok' => true,
            'sessions' => $out,
            'pagination' => [
                'page' => $page,
                'page_size' => $page_size,
                'total' => $count,
            ],
        ]);
    }

    public static function handle_session_create(WP_REST_Request $req)
    {
        global $wpdb;

        $sessions = AdminChatTables::table_sessions();

        $uid = (int) get_current_user_id();
        $title = trim((string)$req->get_param('title'));
        $modelVal = trim((string)$req->get_param('model'));

        $pm = self::parse_model_value($modelVal);
        $model_key = (string)($pm['provider'] ?? '');
        $model_name = (string)($pm['model'] ?? '');

        $now = current_time('mysql');

        $wpdb->insert($sessions, [
            'user_id' => $uid,
            'title' => $title,
            'model_key' => $model_key,
            'model_name' => $model_name,
            'created_at' => $now,
            'updated_at' => $now,
            'deleted_at' => null,
        ]);

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

        return new WP_REST_Response([
            'ok' => true,
            'session' => [
                'id' => $id,
                'title' => $title,
                'model_key' => $model_key,
                'model_name' => $model_name,
                'created_at' => $now,
                'updated_at' => $now,
            ],
        ]);
    }

    public static function handle_session_rename(WP_REST_Request $req)
    {
        global $wpdb;

        $sessions = AdminChatTables::table_sessions();
        $session_id = (int) $req->get_param('id');

        $row = self::get_session_row($session_id);
        if (!$row) {
            return new WP_REST_Response([ 'ok' => false, 'error' => 'not_found' ], 404);
        }

        $title = trim((string)$req->get_param('title'));
        $now = current_time('mysql');

        $wpdb->update(
            $sessions,
            [ 'title' => $title, 'updated_at' => $now ],
            [ 'id' => $session_id ]
        );

        return new WP_REST_Response([
            'ok' => true,
            'session' => [
                'id' => $session_id,
                'title' => $title,
                'updated_at' => $now,
            ],
        ]);
    }

    public static function handle_session_delete(WP_REST_Request $req)
    {
        global $wpdb;

        $sessions = AdminChatTables::table_sessions();
        $messages = AdminChatTables::table_messages();

        $session_id = (int) $req->get_param('id');
        $row = self::get_session_row($session_id);
        if (!$row) {
            return new WP_REST_Response([ 'ok' => false, 'error' => 'not_found' ], 404);
        }

        $wpdb->delete($messages, [ 'session_id' => $session_id ]);
        $wpdb->delete($sessions, [ 'id' => $session_id ]);

        return new WP_REST_Response([ 'ok' => true ]);
    }

    public static function handle_messages_list(WP_REST_Request $req)
    {
        global $wpdb;

        $messages = AdminChatTables::table_messages();

        $session_id = (int) $req->get_param('id');
        $row = self::get_session_row($session_id);
        if (!$row) {
            return new WP_REST_Response([ 'ok' => false, 'error' => 'not_found' ], 404);
        }

        $before_id = (int) ($req->get_param('before_id') ?: 0);
        $limit = (int) ($req->get_param('limit') ?: 50);
        if ($limit < 1) {
            $limit = 50;
        }
        if ($limit > 200) {
            $limit = 200;
        }

        $where = 'session_id=%d';
        $args = [ $session_id ];
        if ($before_id > 0) {
            $where .= ' AND id < %d';
            $args[] = $before_id;
        }

        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT id, role, content, tokens_prompt, tokens_completion, created_at FROM {$messages} WHERE {$where} ORDER BY id DESC LIMIT %d",
            array_merge($args, [ $limit ])
        ), ARRAY_A);

        $rows = is_array($rows) ? $rows : [];
        $rows = array_reverse($rows);

        return new WP_REST_Response([
            'ok' => true,
            'session' => [
                'id' => $session_id,
                'title' => (string)($row['title'] ?? ''),
                'model_key' => (string)($row['model_key'] ?? ''),
                'model_name' => (string)($row['model_name'] ?? ''),
            ],
            'messages' => $rows,
        ]);
    }

    public static function handle_message_send(WP_REST_Request $req)
    {
        global $wpdb;

        $sessions = AdminChatTables::table_sessions();
        $messages = AdminChatTables::table_messages();

        $session_id = (int) $req->get_param('id');
        $row = self::get_session_row($session_id);
        if (!$row) {
            return new WP_REST_Response([ 'ok' => false, 'error' => 'not_found' ], 404);
        }

        $content = trim((string)$req->get_param('content'));
        if ($content === '') {
            return new WP_REST_Response([ 'ok' => false, 'error' => 'content_required' ], 400);
        }

        $modelVal = trim((string)$req->get_param('model'));
        $pm = self::parse_model_value($modelVal);
        $provider = (string)($pm['provider'] ?? '');
        $model = (string)($pm['model'] ?? '');

        $now = current_time('mysql');

        // 插入 user 消息
        $wpdb->insert($messages, [
            'session_id' => $session_id,
            'role' => 'user',
            'content' => $content,
            'tokens_prompt' => null,
            'tokens_completion' => null,
            'created_at' => $now,
        ]);
        $user_msg_id = (int) $wpdb->insert_id;

        // 更新 session 的模型选择（若本次请求携带 model）
        $new_model_key = $provider !== '' ? $provider : (string)($row['model_key'] ?? '');
        $new_model_name = $model !== '' ? $model : (string)($row['model_name'] ?? '');

        $wpdb->update($sessions, [
            'model_key' => $new_model_key,
            'model_name' => $new_model_name,
            'updated_at' => $now,
        ], [ 'id' => $session_id ]);

        $settings = get_option('ai-post', []);
        if (!is_array($settings)) {
            $settings = [];
        }

        $task_config = [
            'disable-language-guard' => true,
            'post-tags-language' => '',
            'custom-language-description' => '',
        ];
        if ($new_model_key !== '') {
            $task_config['task-api-server-type'] = $new_model_key;
        }

        $client = ApiClientService::create_api_client($settings, 'chat', $task_config, $new_model_name);
        if (!is_object($client)) {
            return new WP_REST_Response([ 'ok' => false, 'error' => 'client_create_failed' ], 500);
        }

        if (method_exists($client, 'clearMessages')) {
            $client->clearMessages();
        }

        // 拉取历史消息（最近 20 条）并灌入上下文
        $history = $wpdb->get_results($wpdb->prepare(
            "SELECT role, content FROM {$messages} WHERE session_id=%d ORDER BY id DESC LIMIT 20",
            $session_id
        ), ARRAY_A);
        $history = is_array($history) ? array_reverse($history) : [];

        foreach ($history as $m) {
            $role = strtolower(trim((string)($m['role'] ?? 'user')));
            $c = (string)($m['content'] ?? '');
            if ($c === '') {
                continue;
            }
            if ($role !== 'assistant' && $role !== 'system') {
                $role = 'user';
            }
            if (method_exists($client, 'addMessage')) {
                $client->addMessage($c, $role);
            }
        }

        // ask: 对多数 client 来说，会把 prompt 作为最后一条 user message
        $resp = $client->ask($content);
        $answer = is_array($resp) ? (string)($resp['answer'] ?? '') : '';
        $usage = is_array($resp) ? (array)($resp['usage'] ?? []) : [];

        $tokens_prompt = isset($usage['prompt_tokens']) ? (int)$usage['prompt_tokens'] : null;
        $tokens_completion = isset($usage['completion_tokens']) ? (int)$usage['completion_tokens'] : null;

        $now2 = current_time('mysql');

        $wpdb->insert($messages, [
            'session_id' => $session_id,
            'role' => 'assistant',
            'content' => $answer,
            'tokens_prompt' => $tokens_prompt,
            'tokens_completion' => $tokens_completion,
            'created_at' => $now2,
        ]);
        $assistant_msg_id = (int) $wpdb->insert_id;

        $wpdb->update($sessions, [
            'updated_at' => $now2,
        ], [ 'id' => $session_id ]);

        return new WP_REST_Response([
            'ok' => true,
            'user_message' => [
                'id' => $user_msg_id,
                'role' => 'user',
                'content' => $content,
                'created_at' => $now,
            ],
            'assistant_message' => [
                'id' => $assistant_msg_id,
                'role' => 'assistant',
                'content' => $answer,
                'created_at' => $now2,
            ],
            'usage' => $usage,
        ]);
    }
}
