<?php

namespace XZD\AI\V5\Core;

/**
 * 统一日志系统 — 操作审计 + 自动脱敏 + 多级别
 *
 * 写入 wp_xzd_ai_operation_log 表
 * 自动脱敏: API Key / 邮箱 / 手机号
 */
class Logger
{
    public const LEVEL_INFO = 'info';
    public const LEVEL_WARNING = 'warning';
    public const LEVEL_ERROR = 'error';

    /** 系统内部工具ID → 中文名称映射 */
    private const NAME_MAP = [
        'queue_manager'         => '队列管理器',
        'heartbeat'             => '心跳检测',
        'pipeline_async'        => '流水线异步阶段',
        'pipeline_run'          => '流水线执行',
        'pipeline_skip'         => '流水线跳过',
        'pipeline_retry'        => '流水线重试',
        'pipeline_error'        => '流水线异常',
        'pipeline_process'      => '流水线处理',
        'pipeline_permanent_fail' => '流水线永久失败',
        'pipeline_stage_retry'  => '流水线阶段重试',
        'pipeline_async_retry'  => '异步阶段重试',
        'pipeline_recover'      => '流水线恢复卡死',
        'worker'                => '任务处理器',
        'event_trigger'         => '事件触发器',
        'batch_create'          => '批量任务创建',
        'batch_complete'        => '批量任务完成',
        'batch_cancel'          => '批量任务取消',
        'batch_retry'           => '批量任务重试',
    ];

    /** V8：流水线上下文标志 — 设为true时ToolRegistry跳过单工具日志 */
    private static bool $pipelineContext = false;

    public static function enterPipelineContext(): void { self::$pipelineContext = true; }
    public static function exitPipelineContext(): void { self::$pipelineContext = false; }
    public static function isPipelineContext(): bool { return self::$pipelineContext; }

    /** 将内部 tool_id 解析为可读中文名 */
    public static function resolveName(string $toolId): string
    {
        return self::NAME_MAP[$toolId] ?? $toolId;
    }

    /**
     * 记录工具调用操作
     */
    public static function operation(array $data): ?int
    {
        global $wpdb;
        $table = $wpdb->prefix . 'xzd_ai_operation_log';

        $inserted = $wpdb->insert($table, [
            'tool_id'       => $data['tool_id'] ?? '',
            'tool_name'     => $data['tool_name'] ?? '',
            'category'      => $data['category'] ?? '',
            'target_type'   => $data['target_type'] ?? null,
            'target_id'     => $data['target_id'] ?? null,
            'params'        => isset($data['params']) ? self::maskParams($data['params']) : null,
            'result'        => isset($data['result']) ? wp_json_encode($data['result'], JSON_UNESCAPED_UNICODE) : null,
            'status'        => $data['status'] ?? 'success',
            'error_message' => $data['error_message'] ?? null,
            'undo_data'     => isset($data['undo_data']) ? wp_json_encode($data['undo_data'], JSON_UNESCAPED_UNICODE) : null,
            'undo_window'   => $data['undo_window'] ?? 300,
            'user_id'       => $data['user_id'] ?? get_current_user_id(),
            'operator_id'   => $data['operator_id'] ?? null,
            'session_key'   => $data['session_key'] ?? null,
            'ip'            => $_SERVER['REMOTE_ADDR'] ?? '',
            'cost_tokens'   => $data['cost_tokens'] ?? 0,
            'cost_rmb'      => $data['cost_rmb'] ?? 0,
            'duration_ms'   => $data['duration_ms'] ?? 0,
            'created_at'    => current_time('mysql'),
        ]);

        if ($inserted === false) {
            error_log('[XZD-AI] 日志写入失败: ' . $wpdb->last_error);
            return null;
        }

        return $wpdb->insert_id;
    }

    /**
     * 记录信息日志 — 仅写入 error_log，不写入数据库（减少日志膨胀）
     */
    public static function info(string $toolId, string $message, array $context = []): void
    {
        error_log("[XZD-AI INFO] {$toolId}: {$message} " . json_encode($context, JSON_UNESCAPED_UNICODE));
        // V8：info 级别只写 error_log，不写数据库，等流水线完成时统一写一条汇总
    }

    /**
     * V8：文章流水线处理汇总 — 一篇文章一次处理只写一条日志
     *
     * 将同步+异步所有阶段的结果聚合到一条记录中，
     * 前端可按文章ID筛选，点击展开查看各阶段详情。
     */
    public static function articlePipelineSummary(int $postId, string $event, array $syncResults, array $asyncResults, int $durationMs, string $status): ?int
    {
        $post = get_post($postId);
        $stages = [];
        $totalErrors = 0;

        foreach ($syncResults as $r) {
            $stages[] = [
                'tool'     => $r['tool_id'] ?? '?',
                'name'     => $r['tool_name'] ?? '',
                'type'     => 'sync',
                'success'  => $r['success'] ?? false,
                'message'  => $r['message'] ?? '',
                'duration' => $r['duration_ms'] ?? 0,
            ];
            // V16：区分 skip（无数据需处理）和真实错误，skip 不计入错误
            $isSkip = ($r['error_type'] ?? '') === 'skip';
            if (!($r['success'] ?? true) && !$isSkip) {
                $totalErrors++;
            }
        }
        foreach ($asyncResults as $r) {
            $stages[] = [
                'tool'     => $r['tool_id'] ?? '?',
                'name'     => $r['tool_name'] ?? '',
                'type'     => 'async',
                'success'  => $r['success'] ?? false,
                'message'  => $r['message'] ?? '',
                'duration' => $r['duration_ms'] ?? 0,
            ];
            $isSkip = ($r['error_type'] ?? '') === 'skip';
            if (!($r['success'] ?? true) && !$isSkip) {
                $totalErrors++;
            }
        }

        // V16：区分 success / warning / error
        //   - 全部成功或仅 skip → success（正常完成，只是有些阶段无数据可处理）
        //   - 有真实错误 → warning（流水线部分完成，需关注）
        //   - status 为 failed/permanently_failed → error
        $logStatus = 'success';
        if (in_array($status, ['failed', 'permanently_failed'], true)) {
            $logStatus = 'error';
        } elseif ($totalErrors > 0) {
            $logStatus = self::LEVEL_WARNING;
        }

        return self::operation([
            'tool_id'       => 'article_pipeline',
            'tool_name'     => '文章流水线',
            'category'      => 'pipeline',
            'target_type'   => 'post',
            'target_id'     => $postId,
            'status'        => $logStatus,
            'duration_ms'   => $durationMs,
            'result'        => [
                'post_id'    => $postId,
                'post_title' => $post ? $post->post_title : '(已删除)',
                'event'      => $event,
                'status'     => $status,
                'sync_count' => count($syncResults),
                'async_count' => count($asyncResults),
                'error_count' => $totalErrors,
                'stages'     => $stages,
            ],
            'params'        => ['post_id' => $postId, 'event' => $event],
        ]);
    }

    /**
     * 记录警告日志
     *
     * @param string $category 日志分类（默认 'system'，前端按此筛选）
     */
    public static function warning(string $toolId, string $message, array $context = [], string $category = 'system'): ?int
    {
        return self::operation(array_merge($context, [
            'tool_id'   => $toolId,
            'tool_name' => self::resolveName($toolId),
            'category'  => $category,
            'status'    => self::LEVEL_WARNING,
            'result'    => ['message' => $message],
        ]));
    }

    /**
     * 记录警告日志（带去重）— 同一 tool_id + message 在 $dedupSeconds 秒内不重复写入DB
     *
     * 用于可能频繁触发的恢复/清理动作，防止同一秒并发导致日志刷屏
     */
    public static function warningOnce(string $toolId, string $message, array $context = [], string $category = 'system', int $dedupSeconds = 600): ?int
    {
        $key = 'xzd_log_dedup_' . md5($toolId . ':' . $message);
        if (get_transient($key)) return null;
        set_transient($key, 1, $dedupSeconds);
        return self::warning($toolId, $message, $context, $category);
    }

    /**
     * 记录调试日志 — 仅当 debug_mode 开启时写入 error_log，永不写数据库
     */
    public static function debug(string $toolId, string $message, array $context = []): void
    {
        if (!\XZD\AI\V5\Core\Config::instance()->get('debug_mode', false)) return;
        error_log("[XZD-AI DEBUG] {$toolId}: {$message} " . json_encode($context, JSON_UNESCAPED_UNICODE));
    }

    /**
     * 记录错误日志
     *
     * @param string $category 日志分类（默认 'system'，前端按此筛选）
     */
    public static function error(string $toolId, string $errorMessage, array $context = [], string $category = 'system'): ?int
    {
        return self::operation(array_merge($context, [
            'tool_id'       => $toolId,
            'tool_name'     => self::resolveName($toolId),
            'category'      => $category,
            'status'        => self::LEVEL_ERROR,
            'error_message' => $errorMessage,
        ]));
    }

    /**
     * 参数脱敏 — API Key / 邮箱 / 手机号
     */
    public static function maskParams(array $params): string
    {
        $masked = $params;
        array_walk_recursive($masked, function (&$val, $key) {
            if (!is_string($val)) {
                return;
            }
            $lowerKey = strtolower((string) $key);
            // API Key 完全遮盖
            if (in_array($lowerKey, ['api_key', 'apikey', 'secret', 'password', 'token', 'pexels_key', 'unsplash_key', 'pixabay_key'], true)) {
                $val = '••••••••';
                return;
            }
            // 邮箱部分遮盖
            if (str_contains($val, '@') && filter_var($val, FILTER_VALIDATE_EMAIL)) {
                $parts = explode('@', $val);
                $val = substr($parts[0], 0, 2) . '***@' . $parts[1];
                return;
            }
            // 手机号部分遮盖 (中国大陆 11位)
            if (preg_match('/^1[3-9]\d{9}$/', $val)) {
                $val = substr($val, 0, 3) . '****' . substr($val, -4);
            }
        });
        return wp_json_encode($masked, JSON_UNESCAPED_UNICODE);
    }

    /**
     * 获取操作日志列表
     *
     * 支持的筛选:
     * - tool_id: 精确匹配工具ID
     * - category: 分类筛选
     * - exclude_categories: 排除的分类
     * - status: 状态筛选
     * - user_id: 用户筛选
     * - search: 模糊搜索 tool_name / tool_id / target_type
     * - date_from / date_to: 日期范围
     */
    public static function getLogs(array $filters = [], int $page = 1, int $perPage = 20): array
    {
        global $wpdb;
        $table = $wpdb->prefix . 'xzd_ai_operation_log';

        $where = ['1=1'];
        $bind = [];

        if (!empty($filters['tool_id'])) {
            $where[] = 'tool_id = %s';
            $bind[] = $filters['tool_id'];
        }
        if (!empty($filters['category'])) {
            $where[] = 'category = %s';
            $bind[] = $filters['category'];
        }
        if (!empty($filters['exclude_categories'])) {
            $placeholders = implode(',', array_fill(0, count($filters['exclude_categories']), '%s'));
            $where[] = "category NOT IN ({$placeholders})";
            $bind = array_merge($bind, $filters['exclude_categories']);
        }
        if (!empty($filters['status'])) {
            if ($filters['status'] === 'failed') {
                $where[] = "status != 'success'";
            } else {
                $where[] = 'status = %s';
                $bind[] = $filters['status'];
            }
        }
        if (!empty($filters['user_id'])) {
            $where[] = 'user_id = %d';
            $bind[] = $filters['user_id'];
        }
        if (!empty($filters['search'])) {
            $where[] = '(tool_name LIKE %s OR tool_id LIKE %s OR target_type LIKE %s OR CAST(target_id AS CHAR) LIKE %s)';
            $like = '%' . $wpdb->esc_like($filters['search']) . '%';
            $bind[] = $like;
            $bind[] = $like;
            $bind[] = $like;
            $bind[] = $like;
        }
        if (!empty($filters['date_from'])) {
            $where[] = 'created_at >= %s';
            $bind[] = $filters['date_from'];
        }
        if (!empty($filters['date_to'])) {
            $where[] = 'created_at <= %s';
            $bind[] = $filters['date_to'];
        }

        $whereSql = implode(' AND ', $where);
        $offset = ($page - 1) * $perPage;

        $countSql = "SELECT COUNT(*) FROM {$table} WHERE {$whereSql}";
        $total = (int) (empty($bind)
            ? $wpdb->get_var($countSql)
            : $wpdb->get_var($wpdb->prepare($countSql, $bind)));

        $rowsSql = "SELECT * FROM {$table} WHERE {$whereSql} ORDER BY created_at DESC LIMIT %d OFFSET %d";
        $allBind = array_merge($bind, [$perPage, $offset]);
        $rows = $wpdb->get_results(
            $wpdb->prepare($rowsSql, $allBind),
            ARRAY_A
        );

        return [
            'total' => $total,
            'page'  => $page,
            'pages' => (int) ceil($total / $perPage),
            'items' => $rows ?: [],
        ];
    }

    /**
     * 获取单条日志详情
     */
    public static function getLog(int $id): ?array
    {
        global $wpdb;
        $table = $wpdb->prefix . 'xzd_ai_operation_log';
        $row = $wpdb->get_row(
            $wpdb->prepare("SELECT * FROM {$table} WHERE id = %d", $id),
            ARRAY_A
        );
        return $row ?: null;
    }
}
