<?php

namespace XZD\AI\V5\REST\Controllers;

use XZD\AI\V5\REST\BaseController;
use XZD\AI\V5\Tools\BatchPipeline;
use XZD\AI\V5\Tools\ToolRegistry;
use XZD\AI\V5\Core\Config;
use XZD\AI\V5\Core\Logger;
use WP_REST_Request;
use WP_REST_Response;

/**
 * 流水线 & 批量操作 REST 控制器
 *
 * 端点:
 *   GET    /pipeline/config          — 获取流水线配置
 *   POST   /pipeline/config          — 保存流水线配置
 *   POST   /pipeline/run             — 手动触发流水线
 *   GET    /pipeline/progress/{id}   — 查询进度
 *   POST   /pipeline/cancel/{id}     — 取消任务
 *   POST   /pipeline/retry/{id}      — 重试失败项
 *   GET    /pipeline/stages          — 可用阶段列表
 *   GET    /pipeline/stream/{id}     — SSE 进度推送
 */
class PipelineController extends BaseController
{
    private BatchPipeline $pipeline;

    public function __construct()
    {
        $this->pipeline = new BatchPipeline();
    }

    public function registerRoutes(): void
    {
        $this->registerGet('/pipeline/config', [$this, 'getConfig'], 'manage_options');
        $this->registerPost('/pipeline/config', [$this, 'saveConfig'], 'manage_options');
        $this->registerPost('/pipeline/run', [$this, 'run'], 'manage_options');
        $this->registerGet('/pipeline/progress/(?P<batch_id>[a-zA-Z0-9_]+)', [$this, 'getProgress'], 'manage_options');
        $this->registerPost('/pipeline/cancel/(?P<batch_id>[a-zA-Z0-9_]+)', [$this, 'cancel'], 'manage_options');
        $this->registerPost('/pipeline/retry/(?P<batch_id>[a-zA-Z0-9_]+)', [$this, 'retryFailed'], 'manage_options');
        $this->registerGet('/pipeline/stages', [$this, 'getStages'], 'edit_posts');
        $this->registerGet('/pipeline/stream/(?P<batch_id>[a-zA-Z0-9_]+)', [$this, 'stream'], 'manage_options');

        // 批量操作历史
        $this->registerGet('/pipeline/batches', [$this, 'listBatches'], 'manage_options');

        // 配置变更通知（双轨同步）
        $this->registerGet('/pipeline/config-changed', [$this, 'configChanged'], 'manage_options');

        // 定时扫描进度
        $this->registerGet('/pipeline/scan-progress', [$this, 'scanProgress'], 'manage_options');
    }

    /**
     * GET /pipeline/config
     */
    public function getConfig(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense('free')) return $err;
        $config = Config::instance();
        $pipelineConfig = $config->get('pipeline', []);

        return $this->success([
            'pipeline'      => $pipelineConfig,
            'available_stages' => $this->formatStages($this->pipeline->getAvailableStages()),
            'trigger_events' => [
                ['id' => 'publish_post', 'name' => '发布新文章'],
                ['id' => 'save_post', 'name' => '保存/更新文章'],
                ['id' => 'xzd_schedule_scan', 'name' => '定时扫描(10分钟)'],
            ],
        ]);
    }

    /**
     * POST /pipeline/config
     */
    public function saveConfig(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense()) return $err;
        $body = $this->getBodyParams($request);
        $pipelineConfig = $body['pipeline'] ?? [];

        $config = Config::instance();
        $config->set('pipeline', $pipelineConfig);
        $config->save();

        Logger::info('pipeline_config_saved', '流水线配置已更新');

        return $this->success(null, '流水线配置已保存');
    }

    /**
     * POST /pipeline/run — 创建并执行批量任务
     *
     * Body: {
     *   "post_ids": [1,2,3],      // 或
     *   "range": "recent_100",    // all / recent_N / category_X / date_YYYY-MM-DD_YYYY-MM-DD
     *   "stages": ["generate_tags","generate_seo"],
     *   "options": {"batch_size": 10}
     * }
     */
    public function run(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense()) return $err;
        $body = $this->getBodyParams($request);
        $stages = $body['stages'] ?? [];
        $options = $body['options'] ?? [];

        // 解析文章范围
        $postIds = $body['post_ids'] ?? null;
        if (!is_array($postIds)) {
            $postIds = $this->resolveRange($body['range'] ?? 'recent_10');
        }

        if (empty($postIds)) {
            return $this->error('没有找到符合条件的文章', 'no_posts');
        }

        if (empty($stages)) {
            return $this->error('请至少选择一个处理阶段', 'no_stages');
        }

        // 验证阶段
        foreach ($stages as $stage) {
            if (!ToolRegistry::instance()->has($stage)) {
                return $this->error("未知阶段: {$stage}", 'unknown_stage');
            }
        }

        // 限制批量规模
        if (count($postIds) > 500) {
            $postIds = array_slice($postIds, 0, 500);
        }

        $batchId = $this->pipeline->createBatch($postIds, $stages, $options);
        $progress = $this->pipeline->getProgress($batchId);

        return $this->created([
            'batch_id' => $batchId,
            'progress' => $progress,
        ], '批量任务已创建，共 ' . count($postIds) . ' 篇文章');
    }

    /**
     * GET /pipeline/progress/{batch_id}
     */
    public function getProgress(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense('free')) return $err;
        $batchId = $request->get_param('batch_id');
        $progress = $this->pipeline->getProgress($batchId);

        if ($progress['status'] === 'not_found') {
            return $this->error($progress['message'], 'not_found', 404);
        }

        return $this->success($progress);
    }

    /**
     * POST /pipeline/cancel/{batch_id}
     */
    public function cancel(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense()) return $err;
        $batchId = $request->get_param('batch_id');
        $ok = $this->pipeline->cancel($batchId);

        if (!$ok) {
            return $this->error('任务不存在', 'not_found', 404);
        }

        return $this->success(null, '任务已取消');
    }

    /**
     * POST /pipeline/retry/{batch_id}
     */
    public function retryFailed(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense()) return $err;
        $batchId = $request->get_param('batch_id');
        $count = $this->pipeline->retryFailed($batchId);

        return $this->success(['retry_count' => $count], "已创建重试任务，共 {$count} 篇");
    }

    /**
     * GET /pipeline/stages
     */
    public function getStages(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense('free')) return $err;
        return $this->success($this->formatStages($this->pipeline->getAvailableStages()));
    }

    /**
     * GET /pipeline/stream/{batch_id} — SSE 进度推送
     */
    public function stream(WP_REST_Request $request): void
    {
        if ($err = $this->guardLicense('free')) { echo json_encode(['error' => '插件未授权']); exit; }
        $batchId = $request->get_param('batch_id');

        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache');
        header('Connection: keep-alive');
        header('X-Accel-Buffering: no');

        $lastProgress = '';
        $maxTicks = 300; // 最多 5 分钟
        $tick = 0;

        while ($tick < $maxTicks) {
            $progress = $this->pipeline->getProgress($batchId);

            if ($progress['status'] === 'not_found') {
                echo "data: " . json_encode(['error' => '任务不存在']) . "\n\n";
                ob_flush();
                flush();
                break;
            }

            $current = json_encode($progress);
            if ($current !== $lastProgress) {
                echo "data: {$current}\n\n";
                ob_flush();
                flush();
                $lastProgress = $current;
            }

            if (in_array($progress['status'], ['completed', 'cancelled'])) {
                break;
            }

            usleep(500000); // 0.5 秒轮询
            $tick++;
        }

        exit;
    }

    /**
     * GET /pipeline/batches
     */
    public function listBatches(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense('free')) return $err;
        global $wpdb;
        $prefix = 'xzd_ai_batch_queue_';

        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE %s ORDER BY option_id DESC LIMIT 50",
                $prefix . '%'
            )
        );

        $batches = [];
        foreach ($results as $row) {
            $data = maybe_unserialize($row->option_value);
            if (!$data || !isset($data['meta'])) {
                continue;
            }
            $meta = $data['meta'];
            $batches[] = [
                'batch_id'      => str_replace($prefix, '', $row->option_name),
                'total'         => $meta['total'],
                'completed'     => $meta['completed'],
                'failed'        => $meta['failed'],
                'progress_pct'  => $meta['progress_pct'],
                'status'        => $meta['status'],
                'stages'        => $meta['stages'],
                'created_at'    => $meta['created_at'],
                'finished_at'   => $meta['finished_at'] ?? null,
            ];
        }

        return $this->success($batches);
    }

    /**
     * GET /pipeline/config-changed — 检查配置是否有变更（双轨同步）
     *
     * 前端每 30 秒轮询此端点，检测 AI 对话侧是否修改了配置
     */
    public function configChanged(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense('free')) return $err;
        $lastKnown = (int)($request->get_param('since') ?? 0);
        $changedAt = (int)get_transient('xzd_ai_config_changed');

        if ($changedAt && $changedAt > $lastKnown) {
            return $this->success([
                'changed'    => true,
                'changed_at' => $changedAt,
            ]);
        }

        return $this->success([
            'changed'    => false,
            'changed_at' => $lastKnown,
        ]);
    }

    /**
     * GET /pipeline/scan-progress — 队列与处理统计
     *
     * queue_depth 合并三个来源：PendingQueue option + Action Scheduler actions + WP-Cron events
     */
    public function scanProgress(WP_REST_Request $request): WP_REST_Response
    {
        if ($err = $this->guardLicense('free')) return $err;

        global $wpdb;

        // V14性能：高频轮询端点（JS每30秒调用），加60秒transient缓存
        $cacheKey = 'xzd_scan_progress_cache';
        $cached = get_transient($cacheKey);
        $forceFresh = $request->get_param('fresh') === '1';
        if ($cached && !$forceFresh && is_array($cached)) {
            return $this->success($cached);
        }

        // 队列深度 = WorkerQueue + PendingQueue + AS pending
        $queueDepth = 0;
        if (class_exists(\XZD\AI\V5\Tools\QueueManager::class)) {
            $queueDepth += \XZD\AI\V5\Tools\QueueManager::getQueueDepth();
        }
        if (class_exists(\XZD\AI\V5\Core\PendingQueue::class)) {
            $queueDepth += \XZD\AI\V5\Core\PendingQueue::size();
        }
        // V14性能：AS pending/running 用 COUNT 直查，不拉全量 ID 列表
        $asPending = 0;
        $asRunning = 0;
        if ($wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}actionscheduler_actions'")) {
            $asPending = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$wpdb->prefix}actionscheduler_actions
                 WHERE hook = 'xzd_worker_process' AND status = 'pending'"
            );
            $asRunning = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$wpdb->prefix}actionscheduler_actions
                 WHERE hook = 'xzd_worker_process' AND status = 'in-progress'"
            );
            $queueDepth += $asPending + $asRunning;
        }

        // 总文章数
        $totalPosts = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish'"
        );

        // 已完成流水线数
        $totalProcessed = self::countCompletedPosts();

        // 未处理
        $totalUnprocessed = max(0, $totalPosts - $totalProcessed);

        // 近期新增（1小时/24小时）
        $count1h = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish' AND post_date >= %s",
            date('Y-m-d H:i:s', time() - HOUR_IN_SECONDS)
        ));
        $count24h = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish' AND post_date >= %s",
            date('Y-m-d H:i:s', time() - DAY_IN_SECONDS)
        ));

        // 最近一篇新文章时间
        $lastPostDate = $wpdb->get_var(
            "SELECT post_date FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish' ORDER BY post_date DESC LIMIT 1"
        );

        $result = [
            'queue_depth'       => $queueDepth,
            'queue_worker'      => class_exists(\XZD\AI\V5\Tools\QueueManager::class) ? \XZD\AI\V5\Tools\QueueManager::getQueueDepth() : 0,
            'queue_pending_q'   => class_exists(\XZD\AI\V5\Core\PendingQueue::class) ? \XZD\AI\V5\Core\PendingQueue::size() : 0,
            'queue_as_pending'  => $asPending,
            'queue_as_running'  => $asRunning,
            'total_posts'       => $totalPosts,
            'total_processed'   => $totalProcessed,
            'total_unprocessed' => $totalUnprocessed,
            'recent_1h'         => $count1h,
            'recent_24h'        => $count24h,
            'last_post_at'      => $lastPostDate,
        ];
        // V14：缓存结果60秒（高频轮询端点，JS每30秒调用）
        set_transient($cacheKey, $result, 65);
        return $this->success($result);
    }

    /**
     * 实时统计已完成流水线处理的文章数
     */
    private static function countCompletedPosts(): int
    {
        // V14性能：transient缓存（计数不频繁变化，3000行LIKE扫描可避免）
        $cacheKey = 'xzd_completed_posts_count';
        $cached = get_transient($cacheKey);
        if ($cached !== false) return (int) $cached;

        global $wpdb;
        // V11：统计已处理文章，包含deferred（内容已处理，仅异步阶段延后）
        $count = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->postmeta}
             WHERE meta_key = '_xzd_ai_pipeline_status'
             AND (meta_value LIKE '%\"status\";s:13:\"all_completed\"%'
               OR meta_value LIKE '%\"status\";s:9:\"completed\"%'
               OR meta_value LIKE '%\"status\";s:7:\"partial\"%'
               OR meta_value LIKE '%\"status\";s:8:\"deferred\"%')"
        );
        set_transient($cacheKey, $count, 120); // 2分钟缓存
        return $count;
    }

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

    private function formatStages(array $stages): array
    {
        $formatted = [];
        foreach ($stages as $stage) {
            $formatted[] = [
                'id'          => $stage->id,
                'name'        => $stage->name,
                'description' => $stage->description,
                'category'    => $stage->category,
                'danger'      => $stage->danger,
                'async'       => $stage->pipelineAsync,
            ];
        }
        return $formatted;
    }

    /**
     * 解析文章范围
     */
    private function resolveRange(string $range): array
    {
        $posts = [];

        if (preg_match('/^ids_(.+)$/', $range, $m)) {
            // 按文章ID批量操作，如 ids_1,2,3
            $ids = array_filter(array_map('intval', explode(',', $m[1])), fn($id) => $id > 0);
            $posts = array_slice($ids, 0, 500);
        } elseif (preg_match('/^recent_(\d+)$/', $range, $m)) {
            $limit = (int)$m[1];
            $posts = get_posts([
                'post_type'      => 'post',
                'post_status'    => 'publish',
                'posts_per_page' => min($limit, 500),
                'orderby'        => 'date',
                'order'          => 'DESC',
                'fields'         => 'ids',
            ]);
        } elseif (preg_match('/^category_(\d+)$/', $range, $m)) {
            $posts = get_posts([
                'post_type'      => 'post',
                'post_status'    => 'publish',
                'posts_per_page' => 500,
                'cat'            => (int)$m[1],
                'fields'         => 'ids',
            ]);
        } elseif (preg_match('/^date_(.+)_(.+)$/', $range, $m)) {
            $posts = get_posts([
                'post_type'      => 'post',
                'post_status'    => 'publish',
                'posts_per_page' => 500,
                'date_query'     => [
                    'after'     => $m[1],
                    'before'    => $m[2],
                    'inclusive' => true,
                ],
                'fields'         => 'ids',
            ]);
        } else {
            // 所有文章
            $posts = get_posts([
                'post_type'      => 'post',
                'post_status'    => 'publish',
                'posts_per_page' => 500,
                'fields'         => 'ids',
            ]);
        }

        return $posts;
    }
}
