<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;

require_once __DIR__ . '/../functions/location.php';
// 引入 auth 通用工具函数
require_once __DIR__ . '/auth/utils.php';

function Mirai_handleApi($api) {
    $bufferLevel = ob_get_level();
    ob_start();

    // Sanitize API name
    $api = preg_replace('/[^a-zA-Z0-9_]/', '', (string)$api);
    if ($api === '') {
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(['code' => -1, 'msg' => '未知API', 'success' => false]);
        exit;
    }

    // 处理 RSS Feed 请求 (无需 Session 和 Token)
    if ($api === 'feed' || $api === 'feed_atom') {
        Mirai_handleRssFeed($api);
    }

    // 开启 Session 用于存储验证码
    if (session_status() == PHP_SESSION_NONE) {
        session_start();
    }

    $db = \Typecho\Db::get();
    $options = Mirai_opt();

    $response = ['code' => -1, 'msg' => '未知错误', 'success' => false];

    try {

        $requestMethod = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
        $isGetRequest = $requestMethod === 'GET';
        $noAjaxApis = ['pay_notify', 'pay_return', 'upload_link_img'];
        if (!$isGetRequest && !in_array($api, $noAjaxApis)) {

            if (!isset($_POST['_ajax']) || $_POST['_ajax'] !== '1') {
                throw new Exception('非法访问方式');
            }
        }

        $token = '';
        if (isset($_POST['token']) && $_POST['token'] !== '') {
            $token = $_POST['token'];
        } elseif (isset($_GET['token']) && $_GET['token'] !== '') {
            $token = $_GET['token'];
        } elseif (isset($_COOKIE['mirai_api_sig']) && $_COOKIE['mirai_api_sig'] !== '') {
            $token = $_COOKIE['mirai_api_sig'];
        }
        $security = \Widget\Security::alloc();
        // 验证 mirai_api 的 token（使用时间安全比较）
        $expectedToken = $security->getToken('api');
        if (!hash_equals($expectedToken, $token)) {
            if (!in_array($api, ['get_views', 'pay_notify', 'pay_return', 'archive_list', 'comment_list', 'img_proxy'])) {
                throw new Exception('非法请求');
            }
        }
        switch ($api) {

            case 'auth_login':
                require_once __DIR__ . '/auth/login.php';
                $response = Mirai_api_auth_login();
                break;
            case 'auth_register':
                require_once __DIR__ . '/auth/register.php';
                $response = Mirai_api_auth_register();
                break;
            case 'auth_reset_step2':
                require_once __DIR__ . '/auth/reset.php';
                $response = Mirai_api_auth_reset_step2();
                break;
            case 'auth_validate_code':
                require_once __DIR__ . '/auth/reset.php';
                $response = Mirai_api_auth_validate_code();
                break;
            case 'auth_send_code':
                $result = Mirai_api_send_code_with_check();
                if (!$result['success']) throw new Exception($result['msg']);
                $response = $result;
                break;
            case 'ajaxAddViews':
                require_once __DIR__ . '/interact/views.php';
                $response = Mirai_ajaxAddViews();
                break;
            case 'get_views':
                require_once __DIR__ . '/interact/views.php';
                $response = Mirai_ajaxViews();
                break;
            case 'get_tab_posts':
                require_once __DIR__ . '/interact/tab-posts.php';
                $response = Mirai_ajaxTabPosts();
                break;
            case 'archive_list':
                require_once __DIR__ . '/interact/archive-list.php';
                $response = Mirai_apiArchiveList();
                break;
            case 'comment_list':
                require_once __DIR__ . '/interact/comment-list.php';
                $response = Mirai_apiCommentList();
                break;
            case 'addlike':
                require_once __DIR__ . '/interact/like.php';
                $response = Mirai_ajaxLike();
                break;
            case 'unlike':
                require_once __DIR__ . '/interact/like.php';
                $response = Mirai_ajaxUnlike();
                break;
            case 'collect_article':
                require_once __DIR__ . '/interact/collect.php';
                $response = Mirai_ajaxToggleCollect();
                break;
            case 'send_test_mail':
                $result = Mirai_api_send_test_mail_with_check();
                if (!$result['success']) throw new Exception($result['msg']);
                $response = $result;
                break;
            case 'pay_create_order':
            case 'pay_query_order':
            case 'pay_mark_pending':
            case 'pay_delete_order':
            case 'pay_notify':
            case 'pay_return':
            case 'income_stats':
            case 'income_orders':
            case 'income_transfer':
            case 'balance_withdraw_create':
            case 'balance_withdraw_cancel':
                $response = Mirai_payInterfaceDispatch($api);
                break;

            case 'points_balance':
                require_once __DIR__ . '/points/balance.php';
                $user = Mirai_user();
                $response = Mirai_api_points_balance($db, $user);
                break;
            case 'points_logs':
                require_once __DIR__ . '/points/logs.php';
                $user = Mirai_user();
                $response = Mirai_api_points_logs($db, $user);
                break;
            case 'points_purchase':
                require_once __DIR__ . '/points/purchase.php';
                $user = Mirai_user();
                $response = Mirai_api_points_purchase($db, $user);
                break;
            case 'points_pay':
                require_once __DIR__ . '/points/pay.php';
                $user = Mirai_user();
                $response = Mirai_api_points_pay($db, $user);
                break;

            case 'points_exchange_vip':
                require_once __DIR__ . '/points/exchange-vip-api.php';
                $user = Mirai_user();
                $response = Mirai_api_points_exchange_vip($db, $user);
                break;

            case 'points_exchange_vip_products':
                require_once __DIR__ . '/points/exchange-vip-api.php';
                $user = Mirai_user();
                $response = Mirai_api_points_exchange_vip_products($db, $user);
                break;

            case 'referral_link':
                require_once __DIR__ . '/referral/link.php';
                $user = Mirai_user();
                $response = Mirai_api_referral_link($db, $user);
                break;
            case 'referral_stats':
                require_once __DIR__ . '/referral/stats.php';
                $user = Mirai_user();
                $response = Mirai_api_referral_stats($db, $user);
                break;
            case 'referral_users':
                require_once __DIR__ . '/referral/users.php';
                $user = Mirai_user();
                $response = Mirai_api_referral_users($db, $user);
                break;
            case 'referral_rebate_logs':
                require_once __DIR__ . '/referral/rebate-logs.php';
                $user = Mirai_user();
                $response = Mirai_api_referral_rebate_logs($db, $user);
                break;
            case 'referral_withdraw':
                require_once __DIR__ . '/referral/withdraw.php';
                $user = Mirai_user();
                $response = Mirai_api_referral_withdraw($db, $user);
                break;

            case 'level_info':
                require_once __DIR__ . '/level/info.php';
                $user = Mirai_user();
                $response = Mirai_api_level_info($db, $user);
                break;
            case 'level_logs':
                require_once __DIR__ . '/level/logs.php';
                $user = Mirai_user();
                $response = Mirai_api_level_logs($db, $user);
                break;
            case 'level_rank':
                require_once __DIR__ . '/level/rank.php';
                $user = Mirai_user();
                $response = Mirai_api_level_rank($db, $user);
                break;
            case 'level_admin_adjust':
                require_once __DIR__ . '/level/admin-adjust.php';
                $user = Mirai_user();
                $response = Mirai_api_level_admin_adjust($db, $user);
                break;
            case 'sys_check_update':
            case 'sys_verify':
            case 'sys_activate':
            case 'sys_apply_update':
            case 'sys_update_status':
                if (!function_exists('Mirai_handleLicenseApi')) {
                    throw new Exception('核心模块未加载');
                }
                $response = Mirai_handleLicenseApi($api);
                break;
            case 'core_repair_db':
                $user = Mirai_user();
                if (!$user->pass('administrator', true)) {
                    throw new Exception('权限不足');
                }
                $plugins = \Typecho\Plugin::export();
                if (!isset($plugins['activated']['MiraiCore'])) {
                    throw new Exception('MiraiCore插件未激活');
                }
                if (!class_exists('MiraiCore_Plugin')) {
                    throw new Exception('MiraiCore插件类未找到');
                }
                $changes = MiraiCore_Database_Service::repair();
                if (empty($changes)) {
                    $message = '数据库结构已是最新，无需修复';
                } else {
                    $message = '数据库结构补齐完成';
                }
                $response = [
                    'code' => 0,
                    'success' => true,
                    'message' => $message,
                    'details' => $changes
                ];
                break;

            case 'get_users_vip':
                $currentUser = Mirai_user();
                if ($currentUser->hasLogin() && $currentUser->pass('administrator', true)) {
                    $uids = isset($_POST['uids']) ? explode(',', $_POST['uids']) : [];
                    $uids = array_map('intval', array_filter($uids));
                    if (!empty($uids)) {
                        $users = $db->fetchAll($db->select('uid', 'vip_level', 'vip_exp_date')->from('table.users')->where('uid IN ?', $uids));
                        $data = [];
                        foreach ($users as $u) {
                            $level = intval($u['vip_level'] ?? 0);
                            $data[$u['uid']] = [
                                'level' => $level,
                                'name' => $level > 0 ? (function_exists('Mirai_vipGetName') ? Mirai_vipGetName($level) : ['', '一级会员', '二级会员', '三级会员'][$level]) : '',
                                'exp' => $u['vip_exp_date'] ?? ''
                            ];
                        }
                        $response = ['success' => true, 'data' => $data];
                    } else {
                        $response = ['success' => false, 'msg' => 'No UIDs'];
                    }
                } else {
                    $response = ['success' => false, 'msg' => 'Unauthorized'];
                }
                break;

            case 'getBalances':
                $currentUser = Mirai_user();
                if ($currentUser->hasLogin() && $currentUser->pass('administrator', true)) {
                    $uids = isset($_POST['uids']) ? explode(',', $_POST['uids']) : [];
                    $uids = array_map('intval', array_filter($uids));
                    if (!empty($uids)) {
                        if (function_exists('Mirai_payAdminGetWallets')) {
                            $wallets = Mirai_payAdminGetWallets(1, count($uids), $uids);
                            $data = [];
                            foreach ($wallets['list'] as $wallet) {
                                $data[$wallet['uid']] = ['balance' => (float)$wallet['balance']];
                            }
                            $response = ['success' => true, 'data' => $data];
                        } else {
                            $response = ['success' => false, 'msg' => '支付功能未启用'];
                        }
                    } else {
                        $response = ['success' => true, 'data' => []];
                    }
                } else {
                    $response = ['success' => false, 'msg' => 'Unauthorized'];
                }
                break;

            case 'adjustBalance':
                $currentUser = Mirai_user();
                if ($currentUser->hasLogin() && $currentUser->pass('administrator', true)) {
                    $security = \Widget\Security::alloc();
                    $token = isset($_POST['_token']) ? $_POST['_token'] : '';
                    if ($token !== $security->getToken('mirai-balance-adjust')) {
                        $response = ['success' => false, 'msg' => '安全验证失败'];
                    } else {
                        $uid = isset($_POST['uid']) ? (int)$_POST['uid'] : 0;
                        $amount = isset($_POST['amount']) ? (float)$_POST['amount'] : 0;
                        $type = isset($_POST['type']) ? $_POST['type'] : 'add';
                        $remark = isset($_POST['remark']) ? trim($_POST['remark']) : '';
                        
                        if ($uid <= 0) {
                            $response = ['success' => false, 'msg' => '用户ID无效'];
                        } elseif ($amount <= 0 || !is_finite($amount)) {
                            $response = ['success' => false, 'msg' => '金额无效'];
                        } elseif ($amount > 999999.99) {
                            $response = ['success' => false, 'msg' => '金额超出限制'];
                        } elseif (function_exists('Mirai_payAdminAdjustBalance')) {
                            $actualAmount = $type === 'add' ? $amount : -$amount;
                            $result = Mirai_payAdminAdjustBalance($uid, $actualAmount, 'admin_adjust', $remark ?: '管理员调整');
                            if (!empty($result['success'])) {
                                $response = ['success' => true, 'msg' => ($type === 'add' ? '增加' : '扣除') . '余额成功'];
                            } else {
                                $response = ['success' => false, 'msg' => $result['msg'] ?? '操作失败'];
                            }
                        } else {
                            $response = ['success' => false, 'msg' => '支付功能未启用'];
                        }
                    }
                } else {
                    $response = ['success' => false, 'msg' => 'Unauthorized'];
                }
                break;

            case 'upload_link_img':
                $currentUser = Mirai_user();
                if (!$currentUser->hasLogin()) throw new Exception('请先登录');
                $input = json_decode(file_get_contents('php://input'), true);
                $imgUrl = isset($input['url']) ? trim($input['url']) : '';
                if (empty($imgUrl) || !filter_var($imgUrl, FILTER_VALIDATE_URL)) {
                    $response = ['code' => 1, 'msg' => '无效的图片地址', 'data' => ['errFiles' => [], 'succMap' => new \stdClass]];
                    break;
                }
                $parsed = parse_url($imgUrl);
                $currentHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
                if (isset($parsed['host']) && $parsed['host'] === $currentHost) {
                    $response = ['code' => 0, 'msg' => '', 'data' => ['errFiles' => [], 'succMap' => [$imgUrl => $imgUrl]]];
                    break;
                }
                $imgData = @file_get_contents($imgUrl);
                if ($imgData === false && function_exists('curl_init')) {
                    $ch = curl_init();
                    curl_setopt_array($ch, [CURLOPT_URL => $imgUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 5, CURLOPT_TIMEOUT => 30, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; Mirai/1.0)']);
                    $imgData = curl_exec($ch);
                    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                    curl_close($ch);
                    if ($imgData === false || $httpCode !== 200) {
                        $response = ['code' => 1, 'msg' => '无法下载图片', 'data' => ['errFiles' => [basename($imgUrl)], 'succMap' => new \stdClass]];
                        break;
                    }
                }
                if ($imgData === false) {
                    $response = ['code' => 1, 'msg' => '无法下载图片', 'data' => ['errFiles' => [basename($imgUrl)], 'succMap' => new \stdClass]];
                    break;
                }
                if (strlen($imgData) > 10 * 1024 * 1024) {
                    $response = ['code' => 1, 'msg' => '图片大小超过10MB限制', 'data' => ['errFiles' => [basename($imgUrl)], 'succMap' => new \stdClass]];
                    break;
                }
                $finfo = new \finfo(FILEINFO_MIME_TYPE);
                $mimeType = $finfo->buffer($imgData);
                $mimeToExt = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/gif' => 'gif', 'image/webp' => 'webp', 'image/avif' => 'avif', 'image/bmp' => 'bmp', 'image/svg+xml' => 'svg'];
                $ext = isset($mimeToExt[$mimeType]) ? $mimeToExt[$mimeType] : 'jpg';
                $originalName = basename(parse_url($imgUrl, PHP_URL_PATH));
                if (empty($originalName) || strpos($originalName, '.') === false) $originalName = 'image.' . $ext;
                $date = new \Typecho\Date();
                $uploadDir = defined('__TYPECHO_UPLOAD_DIR__') ? __TYPECHO_UPLOAD_DIR__ : '/usr/uploads';
                $path = \Typecho\Common::url($uploadDir, defined('__TYPECHO_UPLOAD_ROOT_DIR__') ? __TYPECHO_UPLOAD_ROOT_DIR__ : __TYPECHO_ROOT_DIR__) . '/' . $date->year . '/' . $date->month;
                if (!is_dir($path)) {
                    if (!function_exists('Mirai_makeUploadDir')) require_once __DIR__ . '/../modules/upload.php';
                    @Mirai_makeUploadDir($path);
                }
                $fileName = sprintf('%u', crc32(uniqid())) . '.' . $ext;
                $filePath = $path . '/' . $fileName;
                if (file_put_contents($filePath, $imgData) === false) {
                    $response = ['code' => 1, 'msg' => '保存图片失败', 'data' => ['errFiles' => [basename($imgUrl)], 'succMap' => new \stdClass]];
                    break;
                }
                $options = \Typecho\Widget::widget('Widget\Options');
                $newUrl = $options->siteUrl . ltrim(str_replace(__TYPECHO_ROOT_DIR__, '', $filePath), '/');
                $response = ['code' => 0, 'msg' => '', 'data' => ['errFiles' => [], 'succMap' => [$originalName => $newUrl]]];
                break;

            case 'search_users':
                $currentUser = Mirai_user();
                if (!$currentUser->hasLogin()) throw new Exception('请先登录');
                $keyword = isset($_POST['keyword']) ? trim($_POST['keyword']) : '';
                if (empty($keyword) || mb_strlen($keyword) < 1) {
                    $response = ['success' => true, 'users' => []];
                    break;
                }
                $safeKeyword = preg_replace('/[^a-zA-Z0-9\x{4e00}-\x{9fa5}_@.-]/u', '', $keyword);
                $like = '%' . $safeKeyword . '%';
                $users = $db->fetchAll($db->select('uid', 'name', 'screenName')->from('table.users')->where('name LIKE ? OR screenName LIKE ?', $like, $like)->limit(10));
                $result = [];
                foreach ($users as $u) {
                    $result[] = ['uid' => (int)$u['uid'], 'name' => $u['name'], 'screenName' => isset($u['screenName']) ? $u['screenName'] : $u['name']];
                }
                $response = ['success' => true, 'users' => $result];
                break;

            case 'img_proxy':
                require_once __DIR__ . '/img-proxy.php';
                break;

            default:
                throw new Exception('未知API');
        }
    } catch (Throwable $e) {
        $response = ['code' => -1, 'msg' => $e->getMessage(), 'success' => false];
        if ($e->getMessage() === '请先登录') {
            $response['need_login'] = true;
        }
    }

    while (ob_get_level() > $bufferLevel) {
        ob_end_clean();
    }
    if (!headers_sent()) {
        header('Content-Type: application/json; charset=utf-8');
        header('X-Content-Type-Options: nosniff');
        header('Cache-Control: no-store, no-cache, must-revalidate');
    }
    $needAsyncFlush = is_array($response) && !empty($response['_mirai_async_task']) && function_exists('fastcgi_finish_request');
    if ($needAsyncFlush && isset($response['_mirai_async_task'])) {
        unset($response['_mirai_async_task']);
    }
    echo json_encode($response);

    if ($needAsyncFlush) {
        fastcgi_finish_request();
    }

    exit;
}