<?php

namespace XZD\AI\V5\Theme\Adapters;

use XZD\AI\V5\Theme\AdapterBase;

/**
 * Zibll 子比主题适配器 — 深度适配 (28项功能)
 *
 * 优先使用 Zibll 原生函数，降级到直接 wp_usermeta 读写。
 * 所有修改操作记录操作人、原因和变更前后值。
 */
class ZibllAdapter extends AdapterBase
{
    // ===== 身份信息 =====
    public function getThemeName(): string
    {
        $theme = wp_get_theme();
        return $theme->get('Name') ?: 'Zibll 子比主题';
    }

    public function getThemeVersion(): string
    {
        $theme = wp_get_theme();
        return $theme->get('Version') ?: '7.x';
    }

    public function isDarkMode(): bool
    {
        if (function_exists('zib_get_theme_mode')) {
            return zib_get_theme_mode() === 'dark-theme';
        }
        return isset($_COOKIE['theme_mode']) && $_COOKIE['theme_mode'] === 'dark-theme';
    }

    // ===== 能力声明 =====
    public function getCapabilities(): array
    {
        return [
            'points'       => ['available' => function_exists('zibpay_get_user_points'), 'reason' => '', 'source' => 'zibpay_get_user_points / wp_usermeta.points'],
            'balance'      => ['available' => function_exists('zibpay_get_user_balance'), 'reason' => '', 'source' => 'zibpay_get_user_balance / wp_usermeta.balance'],
            'vip'          => ['available' => function_exists('zib_get_user_vip_level'), 'reason' => '', 'source' => 'zib_get_user_vip_level / zibpay_update_user_vip'],
            'blacklist'    => ['available' => function_exists('zib_updata_user_ban'), 'reason' => '', 'source' => 'zib_updata_user_ban / wp_usermeta.banned'],
            'medal'        => ['available' => function_exists('zib_add_user_medal'), 'reason' => '', 'source' => 'zib_add_user_medal / wp_usermeta.medal_details'],
            'notification' => ['available' => class_exists('ZibMsg'), 'reason' => '', 'source' => 'ZibMsg::add / zib_message表'],
            'checkin'      => ['available' => function_exists('zib_user_is_checkined'), 'reason' => '', 'source' => 'zib_user_is_checkined'],
            'invite'       => ['available' => function_exists('zibpay_get_user_invited'), 'reason' => '', 'source' => 'zibpay_get_user_invited / 邀请码系统'],
            'order'        => ['available' => true,  'reason' => '', 'source' => 'wp_zibpay_order 表'],
            'bbs'          => ['available' => post_type_exists('forum_post'), 'reason' => '', 'source' => 'forum_post CPT / WP_Query'],
        ];
    }

    // ===== 积分系统 =====

    public function getPoints(int $userId): int
    {
        if (function_exists('zibpay_get_user_points')) {
            return (int) zibpay_get_user_points($userId);
        }
        return (int) get_user_meta($userId, 'points', true);
    }

    public function addPoints(int $userId, int $amount, string $reason, int $operatorId): array
    {
        if (!$userId) return $this->fail('用户ID无效');
        $before = $this->getPoints($userId);

        // 尝试 Zibll 原生函数 — value 是增量，不是目标值
        $zibUpdated = false;
        if (function_exists('zibpay_update_user_points')) {
            zibpay_update_user_points($userId, [
                'value' => $amount,
                'desc'  => $reason,
            ]);
            $zibUpdated = ($this->getPoints($userId) === $before + $amount);
        }

        // Zibll 函数未生效时，清理重复行并直接写入 points（Zibll 实际读取的键）
        if (!$zibUpdated) {
            global $wpdb;
            $newPoints = $before + $amount;
            $wpdb->delete($wpdb->usermeta, ['user_id' => $userId, 'meta_key' => 'points']);
            $wpdb->insert($wpdb->usermeta, ['user_id' => $userId, 'meta_key' => 'points', 'meta_value' => (string)$newPoints]);
            wp_cache_delete($userId, 'user_meta');
        }

        $after = $this->getPoints($userId);
        return $this->ok('积分增加成功', ['before' => $before, 'after' => $after, 'amount' => $amount]);
    }

    public function deductPoints(int $userId, int $amount, string $reason, int $operatorId): array
    {
        if (!$userId) return $this->fail('用户ID无效');
        $before = $this->getPoints($userId);
        $new = max(0, $before - $amount);

        // 尝试 Zibll 原生函数 — value 是负增量
        $zibUpdated = false;
        if (function_exists('zibpay_update_user_points')) {
            zibpay_update_user_points($userId, [
                'value' => -$amount,
                'desc'  => $reason,
            ]);
            $zibUpdated = ($this->getPoints($userId) === $new);
        }

        // Zibll 函数未生效时，清理重复行并直接写入 points
        if (!$zibUpdated) {
            global $wpdb;
            $wpdb->delete($wpdb->usermeta, ['user_id' => $userId, 'meta_key' => 'points']);
            $wpdb->insert($wpdb->usermeta, ['user_id' => $userId, 'meta_key' => 'points', 'meta_value' => (string)$new]);
            wp_cache_delete($userId, 'user_meta');
        }

        $after = $this->getPoints($userId);
        return $this->ok('积分扣减成功', ['before' => $before, 'after' => $after, 'amount' => $amount]);
    }

    // ===== 余额系统 =====

    public function getBalance(int $userId): float
    {
        if (function_exists('zibpay_get_user_balance')) {
            return (float) zibpay_get_user_balance($userId);
        }
        return (float) get_user_meta($userId, 'balance', true);
    }

    public function addBalance(int $userId, float $amount, string $reason, int $operatorId): array
    {
        if (!$userId) return $this->fail('用户ID无效');
        $before = $this->getBalance($userId);

        if (function_exists('zibpay_update_user_balance')) {
            zibpay_update_user_balance($userId, [
                'value' => $amount,
                'type'  => '管理员充值',
                'desc'  => $reason,
            ]);
        } else {
            $new = round($before + $amount, 2);
            update_user_meta($userId, 'balance', $new);
        }

        $after = $this->getBalance($userId);
        return $this->ok('余额增加成功', ['before' => $before, 'after' => $after, 'amount' => $amount]);
    }

    public function deductBalance(int $userId, float $amount, string $reason, int $operatorId): array
    {
        if (!$userId) return $this->fail('用户ID无效');
        $before = $this->getBalance($userId);

        if (function_exists('zibpay_update_user_balance')) {
            zibpay_update_user_balance($userId, [
                'value' => -$amount,
                'type'  => '管理员扣减',
                'desc'  => $reason,
            ]);
        } else {
            $new = max(0, round($before - $amount, 2));
            update_user_meta($userId, 'balance', $new);
        }

        $after = $this->getBalance($userId);
        return $this->ok('余额扣减成功', ['before' => $before, 'after' => $after, 'amount' => $amount]);
    }

    // ===== VIP 系统 =====

    public function getVipLevel(int $userId): int
    {
        if (function_exists('zib_get_user_vip_level')) {
            $vip = (int) zib_get_user_vip_level($userId);
            if ($vip > 0) return $vip;
        }
        // Zibll 实际读取的 meta key 是 vip_level
        return (int) get_user_meta($userId, 'vip_level', true);
    }

    public function setVipLevel(int $userId, int $level, int $days): array
    {
        if (!$userId) return $this->fail('用户ID无效');
        $before = $this->getVipLevel($userId);
        $until  = $days > 0 ? date('Y-m-d H:i:s', strtotime("+{$days} days")) : 'Permanent';

        // 优先使用 Zibll 原生函数（触发主题钩子）
        if (function_exists('zibpay_update_user_vip')) {
            zibpay_update_user_vip($userId, [
                'vip_level' => $level,
                'exp_date'  => $until,
                'type'      => '管理员设置',
                'desc'      => '管理员通过AI插件设置VIP',
            ]);
        } else {
            // Fallback: 直接写入 Zibll 实际读取的 meta key
            global $wpdb;
            $wpdb->delete($wpdb->usermeta, ['user_id' => $userId, 'meta_key' => 'vip_level']);
            $wpdb->insert($wpdb->usermeta, ['user_id' => $userId, 'meta_key' => 'vip_level', 'meta_value' => (string)$level]);
            if ($until && $until !== 'Permanent') {
                $wpdb->delete($wpdb->usermeta, ['user_id' => $userId, 'meta_key' => 'vip_exp_date']);
                $wpdb->insert($wpdb->usermeta, ['user_id' => $userId, 'meta_key' => 'vip_exp_date', 'meta_value' => $until]);
            }
            wp_cache_delete($userId, 'user_meta');
        }

        return $this->ok('VIP等级设置成功', [
            'before' => $before, 'after' => $level, 'expire' => $until,
        ]);
    }

    public function removeVip(int $userId): array
    {
        if (!$userId) return $this->fail('用户ID无效');
        $before = $this->getVipLevel($userId);

        // 优先使用 Zibll 原生函数
        if (function_exists('zibpay_update_user_vip')) {
            zibpay_update_user_vip($userId, [
                'vip_level' => 0,
                'exp_date'  => date('Y-m-d H:i:s'),
                'type'      => '管理员移除',
                'desc'      => '管理员通过AI插件移除VIP',
            ]);
        }

        // 同时清理 meta（确保兼容性）
        delete_user_meta($userId, 'vip_level');
        delete_user_meta($userId, 'vip_exp_date');
        delete_user_meta($userId, 'vip_level_expired');
        wp_cache_delete($userId, 'user_meta');

        return $this->ok('VIP已移除', ['before' => $before, 'after' => 0]);
    }

    // ===== 封禁/黑名单 =====

    public function isBanned(int $userId): bool
    {
        if (function_exists('zib_user_is_ban')) {
            return (bool) zib_user_is_ban($userId);
        }
        return (bool) get_user_meta($userId, 'banned', true);
    }

    public function banUser(int $userId, string $reason, int $operatorId): array
    {
        if (!$userId) return $this->fail('用户ID无效');

        if (function_exists('zib_updata_user_ban')) {
            zib_updata_user_ban($userId, 1, [
                'reason' => $reason,
                'banned_time' => 7, // 默认7天
                'no_appeal' => false,
            ]);
        } else {
            update_user_meta($userId, 'banned', 1);
            update_user_meta($userId, 'banned_log', serialize([
                'current' => ['reason' => $reason, 'time' => current_time('mysql')],
            ]));
        }

        return $this->ok('用户已封禁', ['user_id' => $userId, 'reason' => $reason]);
    }

    public function unbanUser(int $userId, int $operatorId): array
    {
        if (!$userId) return $this->fail('用户ID无效');

        if (function_exists('zib_updata_user_ban')) {
            zib_updata_user_ban($userId, 0, []);
        }

        delete_user_meta($userId, 'banned');
        delete_user_meta($userId, 'banned_log');
        wp_cache_delete($userId, 'user_meta');

        return $this->ok('用户已解封', ['user_id' => $userId]);
    }

    // ===== 通知系统 =====

    public function sendNotification(int $userId, string $title, string $content, int $senderId): array
    {
        if (!$userId) return $this->fail('用户ID无效');

        // 安全清洗
        $title   = wp_kses_post($title);
        $content = wp_kses_post($content);

        $sent = false;
        $method = 'none';

        // 方式1: ZibMsg 类（最佳，触发所有Zibll消息钩子）
        if (!$sent && class_exists('ZibMsg')) {
            // 检查用户是否允许接收此类消息
            $allowReceive = true;
            if (function_exists('zib_msg_is_allow_receive')) {
                $allowReceive = zib_msg_is_allow_receive($userId, 'system');
            }
            if ($allowReceive) {
                $msgId = \ZibMsg::add([
                    'send_user'    => $senderId ?: 'admin',
                    'receive_user' => $userId,
                    'title'        => $title,
                    'content'      => $content,
                    'type'         => 'system',
                    'status'       => 0,
                    'create_time'  => current_time('mysql'),
                ]);
                if ($msgId) {
                    $sent = true;
                    $method = 'ZibMsg::add';
                }
            }
        }

        // 方式2: 直接写入 Zibll 消息表（降级方案）
        if (!$sent) {
            global $wpdb;
            $msgTable = $wpdb->prefix . 'zib_message';
            if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $msgTable)) === $msgTable) {
                $data = [
                    'receive_user' => $userId,
                    'send_user'    => $senderId ?: 'admin',
                    'title'        => $title,
                    'content'      => $content,
                    'type'         => 'system',
                    'status'       => 0,
                    'create_time'  => current_time('mysql'),
                ];
                $inserted = $wpdb->insert($msgTable, $data);
                if ($inserted && $wpdb->insert_id) {
                    $sent = true;
                    $method = 'zib_message_table';
                }
            }
        }

        // 方式3: user_meta fallback
        if (!$sent) {
            $notifications = get_user_meta($userId, 'xzd_notifications', true) ?: [];
            $notifications[] = [
                'title'   => $title,
                'content' => $content,
                'time'    => current_time('mysql'),
                'sender'  => $senderId,
            ];
            update_user_meta($userId, 'xzd_notifications', $notifications);
            $method = 'user_meta_fallback';
            $sent = true;
        }

        if (!$sent) {
            return $this->fail('通知发送失败：所有方式均未成功');
        }

        wp_cache_delete($userId, 'user_meta');
        return $this->ok("通知已发送 ({$method})", ['method' => $method, 'user_id' => $userId]);
    }

    /**
     * 批量发送站内通知（给多个用户）
     */
    public function sendBulkNotification(array $userIds, string $title, string $content, int $senderId): array
    {
        $success = 0;
        $failed = 0;
        foreach ($userIds as $uid) {
            $r = $this->sendNotification((int)$uid, $title, $content, $senderId);
            if ($r['success']) $success++; else $failed++;
        }
        return $this->ok("通知已批量发送", ['success' => $success, 'failed' => $failed, 'total' => count($userIds)]);
    }

    /**
     * Webhook 通知 — 通用发送
     */
    public function sendWebhook(string $url, array $payload, string $event): array
    {
        if (empty($url)) return $this->fail('Webhook URL 不能为空');

        $response = wp_remote_post($url, [
            'timeout' => 15,
            'headers' => ['Content-Type' => 'application/json'],
            'body'    => json_encode($payload, JSON_UNESCAPED_UNICODE),
        ]);

        if (is_wp_error($response)) {
            return $this->fail('Webhook 发送失败: ' . $response->get_error_message());
        }

        $code = wp_remote_retrieve_response_code($response);
        return $code === 200 ? $this->ok('Webhook 已发送', ['event' => $event])
            : $this->fail("Webhook 返回 HTTP {$code}");
    }

    /**
     * Webhook 通知 — 便捷方法（钉钉/飞书/企业微信格式化）
     */
    public function sendFormattedWebhook(string $webhookUrl, string $title, string $content, string $type = 'dingtalk'): array
    {
        if (empty($webhookUrl)) return $this->fail('Webhook URL 不能为空');

        $payload = match ($type) {
            'feishu' => [
                'msg_type' => 'interactive',
                'card' => [
                    'header' => ['title' => ['content' => $title, 'tag' => 'plain_text']],
                    'elements' => [['tag' => 'div', 'text' => ['content' => $content, 'tag' => 'lark_md']]],
                ],
            ],
            'wecom' => [
                'msgtype' => 'markdown',
                'markdown' => ['content' => "## {$title}\n{$content}"],
            ],
            default => [ // dingtalk
                'msgtype' => 'markdown',
                'markdown' => ['title' => $title, 'text' => "## {$title}\n{$content}"],
            ],
        };

        $response = wp_remote_post($webhookUrl, [
            'timeout' => 15,
            'headers' => ['Content-Type' => 'application/json'],
            'body'    => json_encode($payload, JSON_UNESCAPED_UNICODE),
        ]);

        if (is_wp_error($response)) {
            return $this->fail('Webhook 发送失败: ' . $response->get_error_message());
        }

        $code = wp_remote_retrieve_response_code($response);
        return $code === 200 ? $this->ok('Webhook 已发送', ['type' => $type])
            : $this->fail("Webhook 返回 HTTP {$code}");
    }

    // ===== 签到系统 =====

    public function getCheckinStatus(int $userId): array
    {
        if (function_exists('zib_user_is_checkined')) {
            return [
                'checked_in'       => (bool) zib_user_is_checkined($userId),
                'last_checkin'     => get_user_meta($userId, 'checkin_detail', true) ?: '',
                'consecutive_days' => (int) get_user_meta($userId, 'checkin_continuous_day', true),
            ];
        }

        // Fallback: 读 checkin_detail (Zibll 按日期存的结构化数组)
        $detail = get_user_meta($userId, 'checkin_detail', true) ?: [];
        $today  = wp_date('Y-m-d');
        $ourChecked = is_array($detail) && isset($detail[$today]);

        return [
            'checked_in'       => $ourChecked,
            'last_checkin'     => is_array($detail) ? (end($detail) ? key($detail) : '') : '',
            'consecutive_days' => (int) get_user_meta($userId, 'checkin_continuous_day', true),
        ];
    }

    public function doCheckin(int $userId): array
    {
        if (!$userId) return $this->fail('用户ID无效');

        $status = $this->getCheckinStatus($userId);
        if ($status['checked_in']) {
            return $this->fail('今日已签到，请勿重复签到');
        }

        // Zibll 的 zib_ajax_user_checkin 是 AJAX handler（会 die），不可程序调用
        // 使用内部函数 zib_user_checkin（如果存在）
        if (function_exists('zib_user_checkin')) {
            zib_user_checkin($userId);
        } else {
            // Fallback: 写入 checkin_detail
            $detail = get_user_meta($userId, 'checkin_detail', true) ?: [];
            $detail[wp_date('Y-m-d')] = current_time('mysql');
            update_user_meta($userId, 'checkin_detail', $detail);

            $streak = ((int) get_user_meta($userId, 'checkin_continuous_day', true)) + 1;
            update_user_meta($userId, 'checkin_continuous_day', $streak);
        }

        wp_cache_delete($userId, 'user_meta');
        $streak = (int) get_user_meta($userId, 'checkin_continuous_day', true);

        return $this->ok('签到成功', ['consecutive_days' => $streak ?: 1]);
    }

    // ===== 勋章系统 =====

    public function getMedals(int $userId): array
    {
        $medals = get_user_meta($userId, 'medal_details', true) ?: [];
        if (!is_array($medals) || empty($medals)) {
            return [];
        }
        // 兼容两种格式：
        // - 新格式/Zibll: ['勋章名' => ['name'=>..., ...], ...] → 取 keys
        // - 旧格式: [0 => '勋章名', ...] → 取 values
        $firstKey = array_key_first($medals);
        if (is_int($firstKey)) {
            return array_values($medals);
        }
        return array_keys($medals);
    }

    public function addMedal(int $userId, string $medalId): array
    {
        if (!$userId) return $this->fail('用户ID无效');

        $before = $this->getMedals($userId);

        // 方式1: Zibll 原生函数（仅对Zibll已配置勋章有效）
        if (function_exists('zib_add_user_medal')) {
            @zib_add_user_medal($userId, $medalId);
        }

        // 方式2: 直接写 user_meta（Zibll 关联数组格式），兼容AI自定义勋章名
        $medals = get_user_meta($userId, 'medal_details', true) ?: [];
        if (!is_array($medals)) {
            $medals = [];
        }
        // 规范化：旧索引数组转为关联数组
        if (!empty($medals) && is_int(array_key_first($medals))) {
            $normalized = [];
            foreach ($medals as $v) {
                if (is_string($v) && !empty($v)) {
                    $normalized[$v] = ['name' => $v, 'time' => current_time('Y-m-d H:i:s'), 'remarks' => ''];
                }
            }
            $medals = $normalized;
        }
        if (!isset($medals[$medalId])) {
            $medals[$medalId] = [
                'name'    => $medalId,
                'time'    => current_time('Y-m-d H:i:s'),
                'remarks' => 'AI自动授予',
            ];
            update_user_meta($userId, 'medal_details', $medals);
        }

        wp_cache_delete($userId, 'user_meta');

        // 直接从 user_meta 验证（不走 zib_get_user_medal_details 避免过滤掉自定义勋章）
        $raw = get_user_meta($userId, 'medal_details', true) ?: [];
        $after = is_array($raw) ? (is_int(array_key_first($raw)) ? array_values($raw) : array_keys($raw)) : [];
        if (!in_array($medalId, $after, true)) {
            return $this->fail("勋章添加失败: 验证不通过，before=" . json_encode($before) . " after=" . json_encode($after));
        }

        return $this->ok('勋章已添加', ['medal_id' => $medalId, 'medals' => $after]);
    }

    public function removeMedal(int $userId, string $medalId): array
    {
        if (!$userId) return $this->fail('用户ID无效');

        // 方式1: Zibll 原生函数
        if (function_exists('zib_remove_user_medal')) {
            @zib_remove_user_medal($userId, $medalId);
        }

        // 方式2: 直接清理 user_meta（兼容新旧格式）
        $medals = get_user_meta($userId, 'medal_details', true) ?: [];
        if (!is_array($medals)) {
            $medals = [];
        }
        // 关联数组格式：key 为勋章名
        if (isset($medals[$medalId])) {
            unset($medals[$medalId]);
            update_user_meta($userId, 'medal_details', $medals);
        } else {
            // 旧索引数组格式：搜索并移除值
            $found = false;
            foreach ($medals as $k => $v) {
                $name = is_array($v) ? ($v['name'] ?? '') : $v;
                if ($name === $medalId) {
                    unset($medals[$k]);
                    $found = true;
                }
            }
            if ($found) {
                update_user_meta($userId, 'medal_details', array_values($medals));
            }
        }

        wp_cache_delete($userId, 'user_meta');

        $after = $this->getMedals($userId);
        return $this->ok('勋章已移除', ['medal_id' => $medalId, 'medals' => $after]);
    }

    // ===== 邀请系统 =====

    public function getInviteStats(int $userId): array
    {
        // Zibll 邀请系统由用户生成邀请码，通过 ZibCardPass 管理
        // 尝试多种方式获取邀请统计
        $invited = [];

        if (function_exists('zibpay_get_user_invited')) {
            $invited = zibpay_get_user_invited($userId) ?: [];
        } elseif (class_exists('ZibCardPass')) {
            global $wpdb;
            $table = $wpdb->prefix . 'zibpay_card_password';
            if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table)) === $table) {
                $invited = $wpdb->get_results(
                    $wpdb->prepare("SELECT * FROM {$table} WHERE create_user = %d AND type = 'invite' ORDER BY create_time DESC", $userId),
                    ARRAY_A
                ) ?: [];
            }
        }

        return [
            'invited_count' => count($invited),
            'invited_users' => $invited,
        ];
    }

    // ===== 订单系统 =====

    public function getOrders(int $userId, int $limit = 20): array
    {
        global $wpdb;

        $table = $wpdb->prefix . 'zibpay_order';
        $exists = $wpdb->get_var("SHOW TABLES LIKE '{$table}'") === $table;

        if (!$exists) {
            return [];
        }

        $orders = $wpdb->get_results(
            $wpdb->prepare("SELECT * FROM {$table} WHERE user_id = %d ORDER BY create_time DESC LIMIT %d", $userId, $limit),
            ARRAY_A
        );

        return $orders ?: [];
    }

    public function getShopProducts(int $limit = 100): array
    {
        $products = get_posts([
            'post_type'      => 'shop_product',
            'posts_per_page' => $limit,
            'post_status'    => 'publish',
            'orderby'        => 'date',
            'order'          => 'DESC',
        ]);

        if (empty($products)) return [];

        return array_map(function ($p) {
            $price = get_post_meta($p->ID, 'product_price', true) ?: 0;
            $vipPrice = get_post_meta($p->ID, 'product_vip_price', true) ?: null;
            $stock = get_post_meta($p->ID, 'product_stock', true);
            return [
                'id'          => $p->ID,
                'title'       => $p->post_title,
                'content'     => wp_trim_words($p->post_content, 100),
                'price'       => (float) $price,
                'vip_price'   => $vipPrice !== null ? (float) $vipPrice : null,
                'stock'       => $stock !== '' ? (int) $stock : null,
                'url'         => get_permalink($p->ID),
                'create_time' => $p->post_date,
            ];
        }, $products);
    }

    public function getProductDetail(int $productId): array
    {
        $p = get_post($productId);
        if (!$p || $p->post_type !== 'shop_product') return [];

        $price = get_post_meta($productId, 'product_price', true) ?: 0;
        $vipPrice = get_post_meta($productId, 'product_vip_price', true) ?: null;
        $stock = get_post_meta($productId, 'product_stock', true);
        $type = get_post_meta($productId, 'product_type', true) ?: 'physical';

        return [
            'id'          => $p->ID,
            'title'       => $p->post_title,
            'content'     => $p->post_content,
            'price'       => (float) $price,
            'vip_price'   => $vipPrice !== null ? (float) $vipPrice : null,
            'stock'       => $stock !== '' ? (int) $stock : null,
            'type'        => $type,
            'url'         => get_permalink($p->ID),
            'create_time' => $p->post_date,
        ];
    }

    public function getVipLevels(): array
    {
        if (function_exists('_pz')) {
            $config = _pz('pay_user_vip_options');
            if (is_array($config)) {
                $levels = [];
                foreach ($config as $level => $opt) {
                    if (!empty($opt['name'])) {
                        $levels[] = [
                            'level'       => $level,
                            'name'        => $opt['name'] ?? '',
                            'price'       => (float) ($opt['price'] ?? 0),
                            'description' => $opt['desc'] ?? '',
                            'privileges'  => $opt['privileges'] ?? [],
                        ];
                    }
                }
                if (!empty($levels)) return $levels;
            }
        }

        // Fallback: 从商城商品提取VIP商品
        $products = get_posts([
            'post_type'      => 'shop_product',
            'posts_per_page' => 20,
            'post_status'    => 'publish',
            'meta_key'       => 'product_type',
            'meta_value'     => 'vip',
        ]);

        return array_map(function ($p) {
            return [
                'level'       => 'product_' . $p->ID,
                'name'        => $p->post_title,
                'price'       => (float) (get_post_meta($p->ID, 'product_price', true) ?: 0),
                'description' => wp_trim_words($p->post_content, 30),
                'privileges'  => [],
            ];
        }, $products);
    }

    public function getPointsConfig(): array
    {
        if (function_exists('_pz')) {
            return [
                'signin'        => (int) (_pz('signin_points', 5) ?: 5),
                'post_article'  => (int) (_pz('post_points', 10) ?: 10),
                'comment'       => (int) (_pz('comment_points', 2) ?: 2),
                'daily_signin'  => (int) (_pz('signin_continuous_points', 15) ?: 15),
            ];
        }

        return [
            'signin'        => 5,
            'post_article'  => 10,
            'comment'       => 2,
            'daily_signin'  => 15,
        ];
    }

    // ===== 论坛系统 =====

    public function getForumTopics(int $userId, int $limit = 20): array
    {
        // Zibll BBS 使用 WordPress CPT (forum_post / plate)，不是自定义表
        $topics = get_posts([
            'post_type'      => 'forum_post',
            'author'         => $userId,
            'posts_per_page' => $limit,
            'orderby'        => 'date',
            'order'          => 'DESC',
            'post_status'    => 'publish',
        ]);

        if (empty($topics)) return [];

        return array_map(function ($topic) {
            return [
                'id'          => $topic->ID,
                'title'       => $topic->post_title,
                'content'     => wp_trim_words($topic->post_content, 50),
                'create_time' => $topic->post_date,
                'comment_count' => (int) $topic->comment_count,
            ];
        }, $topics);
    }

    /**
     * 获取版块列表
     */
    public function getForumPlates(array $params = []): array
    {
        $plates = get_posts([
            'post_type'      => 'plate',
            'posts_per_page' => -1,
            'orderby'        => 'menu_order',
            'order'          => 'ASC',
            'post_status'    => 'publish',
        ]);

        return array_map(function ($plate) {
            return [
                'id'          => $plate->ID,
                'name'        => $plate->post_title,
                'description' => $plate->post_content,
                'slug'        => $plate->post_name,
            ];
        }, $plates);
    }

    /**
     * 搜索论坛帖子
     */
    public function searchForumTopics(string $keyword, int $limit = 20, int $offset = 0): array
    {
        $topics = get_posts([
            'post_type'      => 'forum_post',
            's'              => $keyword,
            'posts_per_page' => $limit,
            'orderby'        => 'date',
            'order'          => 'DESC',
            'post_status'    => 'publish',
        ]);

        return array_map(function ($topic) {
            return [
                'id'          => $topic->ID,
                'title'       => $topic->post_title,
                'excerpt'     => wp_trim_words($topic->post_content, 50),
                'create_time' => $topic->post_date,
                'author'      => get_the_author_meta('display_name', $topic->post_author),
            ];
        }, $topics);
    }

    /**
     * 获取论坛统计
     */
    public function getForumStats(): array
    {
        $topicCount = wp_count_posts('forum_post');
        $plateCount = wp_count_posts('plate');

        return [
            'total_topics'  => (int) ($topicCount->publish ?? 0),
            'total_replies' => 0, // BBS回复是WP评论，需另算
            'total_plates'  => (int) ($plateCount->publish ?? 0),
        ];
    }

    // ===== UI 适配 =====

    public function getThemeColors(): array
    {
        $primary = get_theme_mod('main_color', '#0073aa');
        $darkBg  = get_theme_mod('dark_bg_color', '#1e1e1e');

        return [
            'primary'   => $primary ?: '#0073aa',
            'danger'    => get_theme_mod('danger_color', '#dc3232'),
            'success'   => get_theme_mod('success_color', '#46b450'),
            'warning'   => get_theme_mod('warning_color', '#ffb900'),
            'dark_bg'   => $darkBg ?: '#1e1e1e',
            'dark_text' => '#f0f0f0',
            'light_bg'  => '#ffffff',
            'light_text'=> '#333333',
        ];
    }

    public function getBubblePosition(): array
    {
        // Zibll 主题右下角通常有悬浮按钮，需要偏上一些
        return [
            'bottom' => '100px',
            'right'  => '20px',
        ];
    }

    public function getButtonContainerSelector(): ?string
    {
        return '.float-right.round.position-bottom';
    }

    public function hasIntegratedButton(): bool
    {
        return true;
    }

    public function getPageContextRules(): array
    {
        return [
            'postIdPattern' => '/postid-(\d+)|post-(\d+)/',
            'forumClass'    => 'single-forum_post',
        ];
    }

    // ===== SEO 适配 =====
    // Zibll 通过 zib_get_post_meta($id, 'title'/'keywords'/'description') 读取SEO
    // 写入须使用 zib_update_post_meta() 以兼容 CSF 框架

    public function setSEOTitle(int $postId, string $title): bool
    {
        if (function_exists('zib_update_post_meta')) {
            zib_update_post_meta($postId, 'title', $title);
            return true;
        }
        update_post_meta($postId, 'title', $title);
        return true;
    }

    public function setSEODescription(int $postId, string $desc): bool
    {
        if (function_exists('zib_update_post_meta')) {
            zib_update_post_meta($postId, 'description', $desc);
            return true;
        }
        update_post_meta($postId, 'description', $desc);
        return true;
    }

    public function setSEOKeywords(int $postId, array $keywords): bool
    {
        $str = implode(',', $keywords);
        if (function_exists('zib_update_post_meta')) {
            zib_update_post_meta($postId, 'keywords', $str);
            return true;
        }
        update_post_meta($postId, 'keywords', $str);
        return true;
    }

    // ===== Gutenberg 块映射 (Zibll主题专用块) =====

    public function getBlockMapping(): array
    {
        return [
            'paragraph'      => 'core/paragraph',
            'heading'        => 'core/heading',
            'list'           => 'core/list',
            'quote'          => 'zibllblock/quote',
            'code'           => 'zibllblock/enlighter',
            'image'          => 'core/image',
            'table'          => 'core/table',
            'preformatted'   => 'core/preformatted',
            'separator'      => 'core/separator',
            'pullquote'      => 'core/pullquote',
            'details'        => 'core/details',
            'alert'          => 'zibllblock/alert',
            'styled_heading' => 'zibllblock/biaoti',
            'code_highlight' => 'zibllblock/enlighter',
            'styled_quote'   => 'zibllblock/quote',
            'feature_card'   => 'zibllblock/feature',
            'collapse'       => 'zibllblock/collapse',
            'button_group'   => 'zibllblock/buttons',
            'post_card'      => 'zibllblock/postsbox',
            'post_list'      => 'zibllblock/postslists',
            'seamless_img'   => 'zibllblock/seamlessimg',
        ];
    }

    public function buildBlock(string $abstractType, array $data): array
    {
        $content = $data['content'] ?? '';

        switch ($abstractType) {
            // Zibll 专用块
            case 'styled_heading':
                $color = $data['color'] ?? '#1fbc45';
                $tag = $data['tag'] ?? 'h2';
                $html = '<' . $tag . ' class="title-theme" data-color="' . esc_attr($color) . '">'
                    . $content . '</' . $tag . '>';
                return $this->mkBlock('zibllblock/biaoti',
                    ['color' => $color, 'tag_name' => $tag], $html);

            case 'code_highlight':
            case 'code':
                $code = $data['code'] ?? $content;
                $lang = $data['language'] ?? 'generic';
                $title = $data['title'] ?? '';
                $linenums = $data['linenumbers'] ?? true;
                $dataAttrs = ' data-enlighter-language="' . esc_attr($lang) . '"';
                if ($linenums) $dataAttrs .= ' data-enlighter-linenumbers="true"';
                if ($title) $dataAttrs .= ' data-enlighter-title="' . esc_attr($title) . '"';
                $attrs = ['c_language' => $lang];
                if ($linenums) $attrs['linenumbers'] = 'true';
                if ($title) $attrs['title'] = $title;
                return $this->mkBlock('zibllblock/enlighter', $attrs,
                    '<pre class="EnlighterJSRAW"' . $dataAttrs . '>' . esc_html($code) . '</pre>');

            case 'styled_quote':
            case 'quote':
                $color = $data['color'] ?? '';
                $dataAttr = $color ? ' data-color="' . esc_attr($color) . '"' : '';
                $attrs = $color ? ['color' => $color] : [];
                return $this->mkBlock('zibllblock/quote', $attrs,
                    '<div class="quote_q"' . $dataAttr . '><p>' . $content . '</p></div>');

            case 'alert':
                $style = $data['style'] ?? 'info';
                $closeable = !empty($data['closeable']);
                $class = 'alert alert-' . $style;
                $dataAttr = $closeable ? ' data-isclose="true"' : '';
                $attrs = ['typeClass' => $class];
                if ($closeable) $attrs['isChecked'] = 'true';
                return $this->mkBlock('zibllblock/alert', $attrs,
                    '<div class="' . $class . '"' . $dataAttr . '>' . $content . '</div>');

            case 'feature_card':
                $title = $data['title'] ?? '';
                $note = $data['note'] ?? '';
                $icon = $data['icon'] ?? 'fa-star';
                $color = $data['color'] ?? '';
                $iconClass = $color ? ' feature-icon' : ' feature-icon no1';
                $dataAttrs = ' data-icon="' . esc_attr($icon) . '"';
                if ($color) $dataAttrs .= ' data-color="' . esc_attr($color) . '"';
                $attrs = ['icon' => $icon];
                if ($color) $attrs['color'] = $color;
                $html = '<div class="feature"' . $dataAttrs . '>'
                    . '<div class="' . $iconClass . '"><i class="fa ' . esc_attr($icon) . '"></i></div>'
                    . '<div class="feature-title">' . esc_html($title) . '</div>'
                    . '<div class="feature-note">' . esc_html($note) . '</div></div>';
                return $this->mkBlock('zibllblock/feature', $attrs, $html);

            case 'collapse':
                $title = $data['title'] ?? '展开查看';
                $innerBlocks = $data['innerBlocks'] ?? [];
                $open = !empty($data['open']);
                $uid = 'collapse_' . wp_rand(10000, 99999);
                $html = '<div class="panel panel-default" data-isshow="' . ($open ? 'true' : 'false') . '">'
                    . '<div class="biaoti">' . esc_html($title) . '</div>'
                    . '<div class="collapse" id="' . $uid . '">'
                    . $this->renderInnerBlocks($innerBlocks)
                    . '</div></div>';
                return $this->mkBlockWithChildren('zibllblock/collapse',
                    ['id' => $uid, 'isshow' => $open], $html, $innerBlocks);

            case 'button_group':
                $buttons = $data['buttons'] ?? [];
                $alignment = $data['alignment'] ?? 'center';
                $n = count($buttons);
                $colorMap = ['green' => 'c-green', 'blue' => 'c-blue', 'red' => 'c-red',
                    'yellow' => 'c-yellow', 'purple' => 'c-purple'];
                $attrs = ['quantity' => $n, 'radius' => true, 'alignment' => $alignment];
                $html = '<div class="zib-button-group ' . $alignment . '" data-radius="true" data-quantity="' . $n . '">';
                foreach ($buttons as $i => $btn) {
                    $num = $i + 1;
                    $cc = $colorMap[$btn['color'] ?? 'blue'] ?? 'c-blue';
                    $url = $btn['url'] ?? '#';
                    $text = $btn['text'] ?? '按钮' . $num;
                    $html .= '<span class="an_' . $num . ' but-lg ' . $cc . '">'
                        . '<a href="' . esc_url($url) . '">' . esc_html($text) . '</a></span>';
                    $attrs['content' . $num] = $text;
                    $attrs['typeClass' . $num] = 'but-lg ' . $cc;
                }
                $html .= '</div>';
                return $this->mkBlock('zibllblock/buttons', $attrs, $html);

            case 'post_card':
                $pid = (int) ($data['post_id'] ?? 0);
                return $this->mkBlock('zibllblock/postsbox',
                    ['post_id' => (string) $pid],
                    '<div class="posts-box" data-post-id="' . $pid . '"></div>');

            case 'post_list':
                $type = $data['type'] ?? 'related';
                $limit = (int) ($data['limit'] ?? 5);
                return $this->mkBlock('zibllblock/postslists',
                    ['lists_type' => $type, 'lists_limit' => (string) $limit],
                    '<div class="zib-postslists" data-lists-type="' . esc_attr($type)
                    . '" data-lists-limit="' . $limit . '"></div>');

            case 'seamless_img':
                $innerBlocks = $data['innerBlocks'] ?? [];
                $html = '<div class="seamless-img" data-full-container="true">'
                    . $this->renderInnerBlocks($innerBlocks) . '</div>';
                return $this->mkBlockWithChildren('zibllblock/seamlessimg',
                    ['full_container' => 'true'], $html, $innerBlocks);

            // 委托给基类 (WP核心块)
            default:
                return parent::buildBlock($abstractType, $data);
        }
    }

    public function getAIBlockGuidelines(): string
    {
        return <<<'EOT'
## 可用块类型 (Zibll主题)

**标题块 (必须用这个!):**
zibll_biaoti: {"type":"zibll_biaoti","content":"标题","color":"#1fbc45","tag":"h2"}
color可选: #1fbc45(绿) #ff6b6b(红) #4f46e5(蓝)
tag可选: h2(大标题) h3(小标题) h4(子标题)

**文本块:**
paragraph: {"type":"paragraph","content":"段落文字，可含<strong>加粗</strong>和<code>行内代码</code>"}
heading: {"type":"heading","content":"小标题","level":3}

**代码块 (有语法高亮+行号，任何代码都必须用这个!):**
zibll_enlighter: {"type":"zibll_enlighter","code":"代码内容","language":"javascript","title":"示例代码","linenumbers":true}
language: javascript, php, python, html, css, sql, bash, json, java, go, rust, typescript

**亮点卡片 (列特性/优点/功能时用!):**
zibll_feature: {"type":"zibll_feature","title":"亮点名","note":"描述","icon":"fa-star"}
icon建议: fa-star fa-bolt fa-shield fa-rocket fa-check fa-heart fa-eye fa-lock

**提醒框 (重要提示/警告/注意必须用!):**
zibll_alert: {"type":"zibll_alert","content":"提示内容","style":"info"}
style: info(蓝)/success(绿)/warning(黄)/danger(红)

**引言框 (精彩观点/名言引用):**
zibll_quote: {"type":"zibll_quote","content":"引用文字","color":"#1fbc45"}

**列表:**
list: {"type":"list","ordered":false,"items":["项目1","项目2"]}

**折叠框:**
zibll_collapse: {"type":"zibll_collapse","title":"展开查看","content":[{...子块...}]}

**其他:**
table, separator, pullquote, preformatted, zibll_buttons

**核心规则:**
- 第一个块必须是zibll_biaoti (主标题)
- 每个章节开头用zibll_biaoti(h3)作为小标题
- 展示代码必须用zibll_enlighter，禁止用paragraph代替
- 列特性/优点/功能时用3-5个zibll_feature卡片
- 重要提示/警告用zibll_alert，不要用普通段落
- 精彩观点用zibll_quote，不要藏在段落里
- 文章10-25个块，paragraph不超过50%
EOT;
    }

    public function getTextBlockNames(): array
    {
        return ['core/paragraph', 'core/heading', 'core/list',
            'zibllblock/biaoti', 'zibllblock/quote', 'zibllblock/alert',
            'core/preformatted', 'core/pullquote'];
    }

    public function getEditorBlockConfig(): array
    {
        return [
            'textBlocks'        => $this->getTextBlockNames(),
            'hasStyledHeading'  => true,
            'hasCodeHighlight'  => true,
            'hasStyledQuote'    => true,
            'hasAlert'          => true,
            'hasFeatureCard'    => true,
            'hasCollapse'       => true,
            'hasButtonGroup'    => true,
            'hasPostCard'       => true,
            'hasPostList'       => true,
            'hasSeamlessImg'    => true,
            'quickInsertBlocks' => [
                ['id' => 'code_highlight', 'label' => '高亮代码', 'icon' => '💻'],
                ['id' => 'feature_card',   'label' => '亮点卡片', 'icon' => '⭐'],
                ['id' => 'alert',          'label' => '提醒框',   'icon' => '📢'],
                ['id' => 'styled_quote',   'label' => '引言框',   'icon' => '💬'],
                ['id' => 'collapse',       'label' => '折叠框',   'icon' => '📂'],
                ['id' => 'post_card',      'label' => '文章卡片', 'icon' => '📇'],
            ],
            'aiGuidelines'      => $this->getAIBlockGuidelines(),
        ];
    }

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

    private function ok(string $message, array $data = []): array
    {
        return array_merge(['success' => true, 'message' => $message], $data);
    }

    private function fail(string $message): array
    {
        return ['success' => false, 'message' => $message, 'code' => 'error'];
    }
}
