<?php
ob_start();
while (ob_get_level() > 0) {
    ob_end_clean();
}
ob_start();

include(dirname(__DIR__) . '/includes/common.php');
ob_end_clean();

@header('Content-Type: application/json; charset=UTF-8');
@header('Cache-Control: no-cache, must-revalidate');
@header('Pragma: no-cache');
@header('X-Content-Type-Options: nosniff');

if($islogin2 != 1) {
    exit(json_encode(['code' => -1, 'msg' => '请先登录']));
}

$user_id = intval($userrow['zid'] ?? 0);
if ($user_id <= 0) {
    exit(json_encode(['code' => -1, 'msg' => '用户信息获取失败，请重新登录']));
}

require_once dirname(__DIR__) . '/includes/lib/qzone/QzoneService.php';
require_once dirname(__DIR__) . '/includes/lib/qzone/QzoneLoginService.php';
require_once dirname(__DIR__) . '/includes/robot_fun.php';

$act = isset($_GET['act']) ? daddslashes($_GET['act']) : null;

$qzone_node_list_raw = $DB->getColumn("SELECT v FROM bot_config WHERE k='qzone_node_list'");
$qzone_node_list = [];
if ($qzone_node_list_raw) {
    $qzone_node_list = json_decode($qzone_node_list_raw, true);
    if (!is_array($qzone_node_list)) $qzone_node_list = [];
}
$qzone_node_main_name = $DB->getColumn("SELECT v FROM bot_config WHERE k='qzone_node_main_name'");
$qzone_node_main_enabled = $DB->getColumn("SELECT v FROM bot_config WHERE k='qzone_node_main_enabled'");
$qzone_node_main_sort = $DB->getColumn("SELECT v FROM bot_config WHERE k='qzone_node_main_sort'");
$qzone_node_main_name = ($qzone_node_main_name !== null && $qzone_node_main_name !== '') ? $qzone_node_main_name : '主站';
$qzone_node_main_enabled = ($qzone_node_main_enabled === null || $qzone_node_main_enabled === '') ? 1 : intval($qzone_node_main_enabled);
$qzone_node_main_sort = ($qzone_node_main_sort === null || $qzone_node_main_sort === '') ? 0 : intval($qzone_node_main_sort);

$qzone_nodes = [];
foreach ($qzone_node_list as $n) {
    if (!is_array($n)) continue;
    $name = trim((string)($n['name'] ?? ''));
    $enabled = isset($n['enabled']) ? intval($n['enabled']) : 1;
    if ($enabled !== 1) continue;
    $sort = isset($n['sort']) ? intval($n['sort']) : 0;
    $type = isset($n['type']) ? $n['type'] : 'url';

    if ($type === 'socks5') {
        $socks5_host = trim((string)($n['socks5_host'] ?? ''));
        $socks5_port = intval($n['socks5_port'] ?? 0);
        $socks5_user = trim((string)($n['socks5_user'] ?? ''));
        $socks5_pass = trim((string)($n['socks5_pass'] ?? ''));
        if ($name === '' || $socks5_host === '' || $socks5_port <= 0) continue;
        $qzone_nodes[] = [
            'name' => $name,
            'type' => 'socks5',
            'sort' => $sort,
            'socks5_host' => $socks5_host,
            'socks5_port' => $socks5_port,
            'socks5_user' => $socks5_user,
            'socks5_pass' => $socks5_pass
        ];
    } else {
        $url = trim((string)($n['url'] ?? ''));
        if ($name === '' || $url === '') continue;
        $qzone_nodes[] = ['name' => $name, 'url' => $url, 'sort' => $sort, 'type' => 'url'];
    }
}
usort($qzone_nodes, function($a, $b) {
    $sa = intval($a['sort'] ?? 0);
    $sb = intval($b['sort'] ?? 0);
    if ($sa === $sb) return 0;
    return ($sa < $sb) ? -1 : 1;
});

/**
 * 应用节点代理到 CURL 句柄
 * @param resource $ch
 * @param int $node_index 1..n 为外部节点，0 为主站
 * @param array $qzone_nodes 外部节点数组
 */
function qzone_apply_node_proxy($ch, $node_index, $qzone_nodes) {
    // 统一关闭 SSL 验证以提高兼容性
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    
    if ($node_index > 0 && isset($qzone_nodes[$node_index - 1])) {
        $node = $qzone_nodes[$node_index - 1];
        if (isset($node['type']) && $node['type'] === 'socks5') {
            $host = $node['socks5_host'] ?? '';
            $port = intval($node['socks5_port'] ?? 0);
            $user = $node['socks5_user'] ?? '';
            $pass = $node['socks5_pass'] ?? '';
            if ($host !== '' && $port > 0) {
                curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
                if ($user !== '' && $pass !== '') {
                    curl_setopt($ch, CURLOPT_PROXY, $user . ':' . $pass . '@' . $host . ':' . $port);
                } else {
                    curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);
                }
                curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
                curl_setopt($ch, CURLOPT_TIMEOUT, 20);
            }
        }
    } else {
        // 主站节点强制使用 IPv4 以保证会话稳定性
        curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
    }
}

function qzone_extract_cookie_value($cookie, $key) {
    $cookie = (string)$cookie;
    $key = preg_quote((string)$key, '/');
    if (preg_match('/(?:^|;\s*)' . $key . '=([^;]+)/i', $cookie, $m)) {
        return trim($m[1]);
    }
    return '';
}

switch($act) {

case 'get_qzone_nodes':
    $nodesForFront = [];
    foreach ($qzone_nodes as $n) {
        $nodesForFront[] = [
            'name' => $n['name'],
            'type' => $n['type'] ?? 'url',
            'sort' => $n['sort']
        ];
    }
    exit(json_encode([
        'code' => 1,
        'nodes' => $nodesForFront,
        'main_name' => $qzone_node_main_name,
        'main_enabled' => $qzone_node_main_enabled ? 1 : 0,
        'main_sort' => $qzone_node_main_sort
    ]));
break;

case 'init_pwd_web':
    $qq = isset($_POST['qq']) ? trim($_POST['qq']) : '';
    $node_index = isset($_POST['node']) ? intval($_POST['node']) : 0;
    
    if ($qq === '' || !preg_match('/^\d{5,11}$/', $qq)) {
        exit(json_encode(['code' => -1, 'msg' => 'QQ号不正确']));
    }
    
    $rdmX = mt_rand() / mt_getrandmax();
    $initUrl = 'https://xui.ptlogin2.qq.com/cgi-bin/xlogin'
        . '?proxy_url=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv6%2Fportal%2Fproxy.html'
        . '&daid=5&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank'
        . '&appid=549000912&style=22&target=self'
        . '&s_url=' . rawurlencode('https://qzs.qq.com/qzone/v5/loginsucc.html?para=izone')
        . '&pt_no_auth=0'
        . '&r=' . $rdmX;
    
    $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $initUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, $ua);
    qzone_apply_node_proxy($ch, $node_index, $qzone_nodes);
    curl_setopt($ch, CURLOPT_ENCODING, "");
    $resp = curl_exec($ch);
    $curl_err = curl_error($ch);
    curl_close($ch);
    if ($resp === false) exit(json_encode(['code' => -1, 'msg' => '初始化失败: ' . $curl_err]));
    
    $cookieJar = [];
    if (preg_match_all('/Set-Cookie:\s*([^;=]+)=([^;]+);/i', $resp, $m)) {
        for ($i = 0; $i < count($m[1]); $i++) {
            $cookieJar[trim($m[1][$i])] = trim($m[2][$i]);
        }
    }
    
    $pt_login_sig = $cookieJar['pt_login_sig'] ?? '';
    if ($pt_login_sig === '' && preg_match('/g_login_sig\s*=\s*encodeURIComponent\("([^"]+)"\)/i', $resp, $mSig)) {
        $pt_login_sig = $mSig[1];
    }
    if ($pt_login_sig === '') exit(json_encode(['code' => -1, 'msg' => '未获取到 login_sig']));

    $js_ver = '26030415';
    if (preg_match("/ver\/(\d+)/", $resp, $mVer)) {
        $js_ver = $mVer[1];
    }
    
    $rdmC = '0.' . time() . mt_rand(100000, 999999);
    $checkUrl = 'https://ssl.ptlogin2.qq.com/check'
        . '?regmaster=&pt_tea=2&pt_vcode=1'
        . '&uin='.$qq
        . '&appid=549000912'
        . '&js_ver='.$js_ver.'&js_type=1&login_sig='.$pt_login_sig
        . '&u1='.rawurlencode('https://qzs.qq.com/qzone/v5/loginsucc.html?para=izone')
        . '&r=' . $rdmC
        . '&pt_uistyle=25';
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $checkUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, $ua);
    curl_setopt($ch, CURLOPT_REFERER, $initUrl); 
    qzone_apply_node_proxy($ch, $node_index, $qzone_nodes);
    curl_setopt($ch, CURLOPT_ENCODING, "");
    
    $cookieStr = '';
    foreach ($cookieJar as $k => $v) {
        $cookieStr .= $k . '=' . $v . '; ';
    }
    
    $headers = [
        'Cookie: ' . $cookieStr . 'ptui_loginuin='.$qq.'; chkuin='.$qq.'; ',
        'Accept: */*',
        'Accept-Language: zh-CN,zh;q=0.9',
        'Connection: keep-alive',
    ];
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $respCheck = curl_exec($ch);
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $curl_err = curl_error($ch);
    $checkHeaders = substr($respCheck, 0, $headerSize);
    $body = substr($respCheck, $headerSize);
    curl_close($ch);
    
    if (preg_match_all('/Set-Cookie:\s*([^;=]+)=([^;]+);/i', $checkHeaders, $cm)) {
        for ($i = 0; $i < count($cm[1]); $i++) {
            $cookieJar[trim($cm[1][$i])] = trim($cm[2][$i]);
        }
    }
    
    if ($respCheck === false) exit(json_encode(['code' => -1, 'msg' => 'check 调用失败: ' . $curl_err]));
    
    if (preg_match("/ptui_checkVC\((.*)\)/is", $body, $mAll)) {
        $inner = trim($mAll[1]);
        $parts = preg_split('/\s*,\s*/', $inner);
        foreach ($parts as &$p) {
            $p = trim($p, " '\"");
        }
        
        $ret = $parts[0] ?? '';
        $vcode = $parts[1] ?? '';
        $uinHex = $parts[2] ?? '';
        $ptv = $parts[3] ?? '';
        $sid = $parts[6] ?? '';
        
        if ($ret === '0') {
            $_SESSION['qzone_pwd_ctx_'.$user_id.'_'.$qq] = [
                'pt_login_sig' => $pt_login_sig, 
                'ptv' => $ptv,
                'sid' => $sid,
                'js_ver' => $js_ver,
                'o1vId' => md5(uniqid($qq, true)),
                'cookies' => $cookieJar,
                'node' => $node_index
            ];
            exit(json_encode(['code' => 1, 'msg' => 'ok', 'qq' => $qq, 'vcode' => $vcode, 'uin_hex' => $uinHex]));
        } else if ($ret === '1') {
            $_SESSION['qzone_pwd_ctx_'.$user_id.'_'.$qq] = [
                'pt_login_sig' => $pt_login_sig,
                'js_ver' => $js_ver,
                'cookies' => $cookieJar,
                'node' => $node_index
            ];
            exit(json_encode(['code' => 2, 'msg' => '需要滑动验证码', 'qq' => $qq, 'vcode' => $vcode, 'uin_hex' => $uinHex, 'sid' => $sid]));
        } else if ($ret === '2') {
            $subErr = $parts[4] ?? '';
            if ($subErr === '-1') {
                exit(json_encode(['code' => -1, 'msg' => '会话校验失败 (subErr:-1)。这通常是因为 login_sig 与 Cookie 不匹配或请求被拦截。请刷新页面，或在服务器同一网络下手动登录一次以解除风控。']));
            }
            exit(json_encode(['code' => -1, 'msg' => '账号风险 (ret:2, subErr:'.$subErr.')，请前往官网手动登录解除限制。']));
        } else {
            if (preg_match("/ptuiCB\('(.*?)'\)/", $body, $mCB)) {
                $r = explode("','", str_replace("', '", "','", $mCB[1]));
                exit(json_encode(['code' => -1, 'msg' => $r[4] ?? '验证失败']));
            }
            exit(json_encode(['code' => -1, 'msg' => '验证异常 (ret:'.$ret.'): '.$body]));
        }
    } else {
        exit(json_encode(['code' => -1, 'msg' => 'check 格式解析失败']));
    }
break;

case 'finalize_pwd_web':
    $qq = isset($_POST['qq']) ? trim($_POST['qq']) : '';
    $p = isset($_POST['p']) ? trim($_POST['p']) : '';
    $vcode = isset($_POST['vcode']) ? trim($_POST['vcode']) : '';
    $update_qid = intval($_POST['update_qid'] ?? 0);
    $sms_code = isset($_POST['sms_code']) ? trim($_POST['sms_code']) : '';
    $ticket = isset($_POST['ticket']) ? trim($_POST['ticket']) : '';
    $node_index = isset($_POST['node']) ? intval($_POST['node']) : -1;
    
    if ($qq === '' || !preg_match('/^\d{5,11}$/', $qq)) exit(json_encode(['code' => -1, 'msg' => 'QQ号不正确']));
    if ($p === '' || $vcode === '') exit(json_encode(['code' => -1, 'msg' => '参数缺失']));
    
    $ctx = $_SESSION['qzone_pwd_ctx_'.$user_id.'_'.$qq] ?? null;
    if (!$ctx || empty($ctx['pt_login_sig'])) exit(json_encode(['code' => -1, 'msg' => '上下文失效，请重试']));
    
    if ($ticket !== '') {
        $ctx['ptv'] = $ticket;
    }
    
    if ($node_index === -1) {
        $node_index = intval($ctx['node'] ?? 0);
    }
    
    $pt_login_sig = $ctx['pt_login_sig'];
    $ptv = $ctx['ptv'] ?? '';
    $o1vId = $ctx['o1vId'] ?? md5(uniqid($qq, true));
    $cookies = $ctx['cookies'] ?? [];
    $js_ver = $ctx['js_ver'] ?? '26030415';
    
    $sms_ticket = isset($_POST['sms_ticket']) ? trim($_POST['sms_ticket']) : ($ctx['sms_ticket'] ?? '');
    
    $sid = $ctx['sid'] ?? $cookies['sid'] ?? '';
    $ptdrvs = $cookies['ptdrvs'] ?? '';
    $pt_ev_token = $cookies['pt_ev_token'] ?? '';
    
    $pt_vcode_v1 = (strpos($vcode, '!') !== false) ? 0 : 1;
    
    $action = '5-10-' . time() . mt_rand(100, 999);
    $pt_js_version = 'b515fdc3';
    
    $loginUrl = 'https://ssl.ptlogin2.qq.com/login'
        . '?u=' . urlencode($qq)
        . '&verifycode=' . urlencode($vcode)
        . '&pt_vcode_v1=' . $pt_vcode_v1
        . '&pt_verifysession_v1=' . urlencode($ptv)
        . '&p=' . urlencode($p)
        . '&pt_randsalt=2'
        . '&u1=' . urlencode('https://qzs.qq.com/qzone/v5/loginsucc.html?para=izone')
        . '&ptredirect=0'
        . '&h=1&t=1&g=1&from_ui=1&ptlang=2052'
        . '&action=' . $action
        . '&js_ver=' . $js_ver
        . '&js_type=1&login_sig=' . $pt_login_sig
        . '&pt_uistyle=40&aid=549000912&daid=5'
        . '&ptdrvs=' . urlencode($ptdrvs)
        . '&sid=' . urlencode($sid);
    
    if ($pt_ev_token) $loginUrl .= '&pt_ev_token=' . urlencode($pt_ev_token);
    if ($o1vId) $loginUrl .= '&o1vId=' . urlencode($o1vId);
    if ($sms_code) $loginUrl .= '&pt_sms_code=' . urlencode($sms_code);
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $loginUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
    $referrer = 'https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=0&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_no_auth=0';
    curl_setopt($ch, CURLOPT_REFERER, $referrer);
    qzone_apply_node_proxy($ch, $node_index, $qzone_nodes);
    
    $cookieStr = '';
    foreach ($cookies as $k => $v) {
        $cookieStr .= $k . '=' . $v . '; ';
    }
    if ($sms_code && $sms_ticket) {
        $cookieStr .= 'pt_sms_ticket=' . $sms_ticket . '; pt_sms=' . $sms_code . '; ';
    }
    $cookieSend = $cookieStr . 'ptui_loginuin='.$qq.'; chkuin='.$qq.'; ';
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Cookie: '.$cookieSend]);
    
    $resp = curl_exec($ch);
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $curl_err = curl_error($ch);
    $loginHeaders = substr($resp, 0, $headerSize);
    $loginBody = substr($resp, $headerSize);
    curl_close($ch);
    
    if ($resp === false) exit(json_encode(['code' => -1, 'msg' => '登录请求失败: ' . $curl_err]));
    
    // 解析 ptuiCB('0','0','http://...','0','登录成功','nickname')
    if (!preg_match("/ptuiCB\('(.*?)'\)/", $loginBody, $arr)) {
        exit(json_encode(['code' => -1, 'msg' => '登录返回解析失败: '.$loginBody]));
    }
    
    // 提取 login 阶段的 Cookie (如 skey, superkey)
    $loginCookies = [];
    if (preg_match_all('/Set-Cookie:\s*([^;=]+)=([^;]*)/i', $loginHeaders, $cm)) {
        foreach ($cm[1] as $index => $name) {
            $loginCookies[trim($name)] = trim($cm[2][$index]);
        }
    }
    
    $r = explode("','", str_replace("', '", "','", $arr[1]));
    if ($r[0] != 0) {
        $msg = $r[4] ?? '登录失败';
        $retCode = intval($r[0]);
        
        // 识别特定错误码
        if ($retCode === 10009) {
            // 提取 sms_ticket
            $sms_ticket = '';
            if (preg_match('/pt_sms_ticket=([^;=]+)/i', $loginHeaders, $mST)) {
                $sms_ticket = trim($mST[1]);
            }
            
            // 更新 ptdrvs (如果有)
            if (preg_match('/ptdrvs=([^;=]+)/i', $loginHeaders, $mDRV)) {
                $ctx['cookies']['ptdrvs'] = trim($mDRV[1]);
            }
            
            $ctx['sms_ticket'] = $sms_ticket;
            $_SESSION['qzone_pwd_ctx_'.$user_id.'_'.$qq] = $ctx;
            
            exit(json_encode([
                'code' => 10009, 
                'msg' => '请通过密保手机 ' . $msg . ' 获取短信验证码',
                'sms_ticket' => $sms_ticket
            ]));
        } elseif ($retCode === 10005 || $retCode === 10006 || $retCode === 22009) {
            $msg = '登录环境异常（异地登录或IP存在风险），请使用QQ手机版扫码登录，或在服务器同一网络下手动登录官网解除风控。';
        } elseif (preg_match('/^\d{3}\*+\d{2}$/', $msg)) {
            $msg = '需要短信验证，请通过密保手机 ' . $msg . ' 进行验证。建议先关闭设备锁或手动登录官网解封。';
        }
        
        exit(json_encode(['code' => -1, 'msg' => $msg]));
    }
    
    $jump = $r[2] ?? '';
    if ($jump === '') exit(json_encode(['code' => -1, 'msg' => '跳转地址缺失']));
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $jump);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, Gecko) Chrome/120.0.0.0 Safari/537.36');
    curl_setopt($ch, CURLOPT_REFERER, 'https://xui.ptlogin2.qq.com/');
    qzone_apply_node_proxy($ch, $node_index, $qzone_nodes);
    
    $currentCookies = array_merge($cookies, $loginCookies);
    $cookieSendStr = '';
    foreach ($currentCookies as $k => $v) {
        $cookieSendStr .= $k . '=' . $v . '; ';
    }
    $cookieSendStr .= 'ptui_loginuin='.$qq.'; chkuin='.$qq.'; ';
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Cookie: '.$cookieSendStr]);
    
    $resp2 = curl_exec($ch);
    $curl_err = curl_error($ch);
    curl_close($ch);
    
    if ($resp2 === false) exit(json_encode(['code' => -1, 'msg' => '跳转确认失败: ' . $curl_err]));
    
    $jumpCookies = [];
    if (preg_match_all('/Set-Cookie:\s*([^;=]+)=([^;]*)/i', $resp2, $cm)) {
        foreach ($cm[1] as $index => $name) {
            $jumpCookies[trim($name)] = trim($cm[2][$index]);
        }
    }
    
    $finalCookies = array_merge($currentCookies, $jumpCookies);
    
    $skey = $finalCookies['skey'] ?? '';
    $pskey = $finalCookies['p_skey'] ?? '';
    $superkey = $finalCookies['superkey'] ?? '';
    
    if ($skey === '' || $pskey === '') {
        if ($skey === '' && preg_match('/skey=(@.{9});/', $resp2, $mSkey)) $skey = $mSkey[1];
        if ($skey === '' && preg_match('/skey=(@.{9});/', $loginHeaders, $mSkey)) $skey = $mSkey[1];
        if ($pskey === '' && preg_match('/p_skey=([^;]+);/', $resp2, $mPskey)) $pskey = $mPskey[1];
    }
    
    if ($skey === '' || $pskey === '') {
        exit(json_encode(['code' => -1, 'msg' => '登录成功但未获取到关键Cookie (skey/p_skey)，请检查环境。skey:'.$skey.', pskey:'.$pskey]));
    }
    
    $gtk = QzoneService::qzoneGetGTK($pskey);
    $qzonetoken = QzoneService::qzoneGetQzonetoken($qq, $skey, $pskey);
    $nickname = trim($r[5] ?? 'QQ用户');
    $skeyDb = daddslashes($skey);
    $pskeyDb = daddslashes($pskey);
    $superkeyDb = daddslashes($superkey);
    $gtkDb = daddslashes($gtk);
    $qzonetokenDb = daddslashes($qzonetoken);
    $nicknameDb = daddslashes($nickname);
    if ($update_qid > 0) {
        $target = qzone_validate_qid_ownership($update_qid, $user_id);
        if (isset($target['error'])) exit(json_encode(['code' => -1, 'msg' => $target['error']]));
        if ((string)$target['qq'] !== (string)$qq) exit(json_encode(['code' => -2, 'msg' => '密码登录QQ不匹配，请使用QQ '.$target['qq']]));
        $DB->exec("UPDATE " . DBQZ . "qzone_qq SET skey='{$skeyDb}', pskey='{$pskeyDb}', superkey='{$superkeyDb}', gtk='{$gtkDb}', qzonetoken='{$qzonetokenDb}', nickname='{$nicknameDb}', login_status=0, login_time=NOW() WHERE id='{$update_qid}'");
        exit(json_encode(['code' => 0, 'msg' => '状态更新成功']));
    }
    $existId = $DB->getColumn("SELECT id FROM " . DBQZ . "qzone_qq WHERE qq='".daddslashes($qq)."'");
    if ($existId) {
        $DB->exec("UPDATE " . DBQZ . "qzone_qq SET user_id='{$user_id}', skey='{$skeyDb}', pskey='{$pskeyDb}', superkey='{$superkeyDb}', gtk='{$gtkDb}', qzonetoken='{$qzonetokenDb}', nickname='{$nicknameDb}', login_status=0, login_time=NOW() WHERE id='{$existId}'");
    } else {
        $DB->exec("INSERT INTO " . DBQZ . "qzone_qq (user_id, qq, nickname, skey, pskey, superkey, gtk, qzonetoken, login_status, login_time, vip_time) VALUES ('{$user_id}', '".daddslashes($qq)."', '{$nicknameDb}', '{$skeyDb}', '{$pskeyDb}', '{$superkeyDb}', '{$gtkDb}', '{$qzonetokenDb}', 0, NOW(), NOW())");
    }
    exit(json_encode(['code' => 0, 'msg' => '密码登录成功']));
break;

case 'send_sms_web':
    $qq = isset($_POST['qq']) ? trim($_POST['qq']) : '';
    $node_param = isset($_POST['node']) ? intval($_POST['node']) : -1;
    
    if ($qq === '' || !preg_match('/^\d{5,11}$/', $qq)) exit(json_encode(['code' => -1, 'msg' => 'QQ号不正确']));
    
    $ctx = $_SESSION['qzone_pwd_ctx_'.$user_id.'_'.$qq] ?? null;
    if (!$ctx || empty($ctx['sms_ticket'])) exit(json_encode(['code' => -1, 'msg' => '短信会话失效，请重试登录']));
    
    $sms_ticket = $ctx['sms_ticket'];
    $cookies = $ctx['cookies'] ?? [];
    
    // 优先使用前端传来的 node，否则使用 ctx 中的
    $node_index = ($node_param !== -1) ? $node_param : intval($ctx['node'] ?? 0);
    
    $url = 'https://ssl.ptlogin2.qq.com/send_sms_code?bkn=&uin='.$qq.'&aid=549000912&pt_sms_ticket='.$sms_ticket;
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
    curl_setopt($ch, CURLOPT_REFERER, 'https://ui.ptlogin2.qq.com/web/verify/iframe?uin='.$qq.'&appid=549000912');
    qzone_apply_node_proxy($ch, $node_index, $qzone_nodes);
    
    $cookieStr = '';
    foreach ($cookies as $k => $v) {
        $cookieStr .= $k . '=' . $v . '; ';
    }
    $cookieStr .= 'pt_sms_ticket='.$sms_ticket.'; ';
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Cookie: '.$cookieStr]);
    
    $resp = curl_exec($ch);
    $curl_err = curl_error($ch);
    curl_close($ch);
    
    if ($resp === false) exit(json_encode(['code' => -1, 'msg' => '短信请求失败: ' . $curl_err]));
    
    if (preg_match("/ptui_sendSMS_CB\('(.*?)'\)/", $resp, $arr)){
        $r = explode("', '", $arr[1]);
        if ($r[0] == '10012') {
            exit(json_encode(['code' => 0, 'msg' => '短信验证码发送成功！']));
        } else {
            exit(json_encode(['code' => -1, 'msg' => $r[1] ?? '短信发送失败，请重试 (ret:'.$r[0].')']));
        }
    } else {
        exit(json_encode(['code' => -1, 'msg' => '接口响应异常: '.$resp]));
    }
break;

case 'get_cloud_qq_options':
    if (($conf['cloud_enabled'] ?? '1') != '1') {
        exit(json_encode(['code' => -1, 'msg' => '云端系统未开启']));
    }
    // 标准 pre_qq 无 qq_name 列；统一用固定字段避免先执行失败 SQL
    $rows = $DB->getAll("SELECT id,qq,login_zt FROM pre_qq WHERE zid='{$user_id}' ORDER BY id DESC");
    if ($rows === false) {
        exit(json_encode(['code' => -1, 'msg' => '获取账号库失败']));
    }
    $data = [];
    foreach ((array)$rows as $row) {
        $data[] = [
            'id' => intval($row['id'] ?? 0),
            'qq' => (string)($row['qq'] ?? ''),
            'nickname' => (string)($row['qq_name'] ?? ($row['nickname'] ?? '')),
            'login_zt' => intval($row['login_zt'] ?? 0)
        ];
    }
    exit(json_encode(['code' => 1, 'data' => $data]));
break;

case 'get_dg_qq_options':
    if (($conf['dg_open'] ?? '0') != '1') {
        exit(json_encode(['code' => -1, 'msg' => '代挂系统未开启']));
    }
    // 标准 pre_dg_qq 无 qq_name；与 qq 列表页一致按 zid 筛选
    $rows = $DB->getAll("SELECT id,qq,login_zt FROM pre_dg_qq WHERE zid='{$user_id}' ORDER BY id DESC");
    if ($rows === false) {
        exit(json_encode(['code' => -1, 'msg' => '获取账号库失败']));
    }
    $data = [];
    foreach ((array)$rows as $row) {
        $data[] = [
            'id' => intval($row['id'] ?? 0),
            'qq' => (string)($row['qq'] ?? ''),
            'nickname' => (string)($row['qq_name'] ?? ($row['nickname'] ?? '')),
            'login_zt' => intval($row['login_zt'] ?? 0)
        ];
    }
    exit(json_encode(['code' => 1, 'data' => $data]));
break;

case 'import_cloud_qq':
    if (($conf['cloud_enabled'] ?? '1') != '1') {
        exit(json_encode(['code' => -1, 'msg' => '云端系统未开启']));
    }
    $cloudId = intval($_POST['cloud_id'] ?? 0);
    if ($cloudId <= 0) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $cloud = $DB->getRow("SELECT id,qq,qq_name,skey,pskey,superkey,cookie,login_zt FROM pre_qq WHERE id='{$cloudId}' AND zid='{$user_id}' LIMIT 1");
    if ($cloud === false || !$cloud) {
        $cloud = $DB->getRow("SELECT id,qq,skey,pskey,superkey,cookie,login_zt FROM pre_qq WHERE id='{$cloudId}' AND zid='{$user_id}' LIMIT 1");
    }
    if ($cloud === false || !$cloud) {
        $cloud = $DB->getRow("SELECT id,qq,cookie,login_zt FROM pre_qq WHERE id='{$cloudId}' AND zid='{$user_id}' LIMIT 1");
    }
    if ($cloud === false || !$cloud) {
        $cloud = $DB->getRow("SELECT id,qq,login_zt FROM pre_qq WHERE id='{$cloudId}' AND zid='{$user_id}' LIMIT 1");
    }
    if (!$cloud) exit(json_encode(['code' => -1, 'msg' => '云端QQ不存在']));

    $qq = trim((string)($cloud['qq'] ?? ''));
    if ($qq === '' || !preg_match('/^\d{5,11}$/', $qq)) exit(json_encode(['code' => -1, 'msg' => '云端QQ号无效']));

    $skey = trim((string)($cloud['skey'] ?? ''));
    $pskey = trim((string)($cloud['pskey'] ?? ''));
    $superkey = trim((string)($cloud['superkey'] ?? ''));
    $cookie = (string)($cloud['cookie'] ?? '');
    if ($skey === '') $skey = qzone_extract_cookie_value($cookie, 'skey');
    if ($pskey === '') $pskey = qzone_extract_cookie_value($cookie, 'p_skey');
    if ($superkey === '') $superkey = qzone_extract_cookie_value($cookie, 'superkey');

    $nickname = trim((string)($cloud['qq_name'] ?? ($cloud['nickname'] ?? '')));
    $gtk = '';
    $qzonetoken = '';
    $loginStatus = 1;
    if ($skey !== '' && $pskey !== '') {
        $gtk = QzoneService::qzoneGetGTK($pskey);
        $qzonetoken = QzoneService::qzoneGetQzonetoken($qq, $skey, $pskey);
        $loginStatus = 0;
    }

    $qqDb = daddslashes($qq);
    $nicknameDb = daddslashes($nickname);
    $skeyDb = daddslashes($skey);
    $pskeyDb = daddslashes($pskey);
    $superkeyDb = daddslashes($superkey);
    $gtkDb = daddslashes($gtk);
    $qzonetokenDb = daddslashes($qzonetoken);

    $existId = intval($DB->getColumn("SELECT id FROM " . DBQZ . "qzone_qq WHERE qq='{$qqDb}' LIMIT 1"));
    if ($existId > 0) {
        $DB->exec("UPDATE " . DBQZ . "qzone_qq SET user_id='{$user_id}', nickname='{$nicknameDb}', skey='{$skeyDb}', pskey='{$pskeyDb}', superkey='{$superkeyDb}', gtk='{$gtkDb}', qzonetoken='{$qzonetokenDb}', login_status='{$loginStatus}', login_time=NOW() WHERE id='{$existId}'");
        qzone_ensure_config_exists($existId);
        $msg = ($loginStatus === 0) ? '已从云端版同步到秒赞版' : '已从云端版添加到秒赞版（未获取到Cookie，需在秒赞版更新状态）';
        exit(json_encode(['code' => 0, 'msg' => $msg]));
    }

    $DB->exec("INSERT INTO " . DBQZ . "qzone_qq (user_id, qq, nickname, skey, pskey, superkey, gtk, qzonetoken, login_status, login_time, vip_time) VALUES ('{$user_id}', '{$qqDb}', '{$nicknameDb}', '{$skeyDb}', '{$pskeyDb}', '{$superkeyDb}', '{$gtkDb}', '{$qzonetokenDb}', '{$loginStatus}', NOW(), NOW())");
    $newId = intval($DB->lastInsertId());
    qzone_ensure_config_exists($newId);
    $msg = ($loginStatus === 0) ? '已从云端版添加到秒赞版' : '已从云端版添加到秒赞版（未获取到Cookie，需在秒赞版更新状态）';
    exit(json_encode(['code' => 0, 'msg' => $msg]));
break;

case 'import_dg_qq':
    if (($conf['dg_open'] ?? '0') != '1') {
        exit(json_encode(['code' => -1, 'msg' => '代挂系统未开启']));
    }
    $dgId = intval($_POST['dg_id'] ?? 0);
    if ($dgId <= 0) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $dg = $DB->getRow("SELECT id,qq,qq_name,skey,pskey,superkey,cookie,login_zt FROM pre_dg_qq WHERE id='{$dgId}' AND zid='{$user_id}' LIMIT 1");
    if ($dg === false || !$dg) {
        $dg = $DB->getRow("SELECT id,qq,skey,pskey,superkey,cookie,login_zt FROM pre_dg_qq WHERE id='{$dgId}' AND zid='{$user_id}' LIMIT 1");
    }
    if ($dg === false || !$dg) {
        $dg = $DB->getRow("SELECT id,qq,cookie,login_zt FROM pre_dg_qq WHERE id='{$dgId}' AND zid='{$user_id}' LIMIT 1");
    }
    if ($dg === false || !$dg) {
        $dg = $DB->getRow("SELECT id,qq,login_zt FROM pre_dg_qq WHERE id='{$dgId}' AND zid='{$user_id}' LIMIT 1");
    }
    if (!$dg) exit(json_encode(['code' => -1, 'msg' => '代挂QQ不存在']));

    $qq = trim((string)($dg['qq'] ?? ''));
    if ($qq === '' || !preg_match('/^\d{5,11}$/', $qq)) exit(json_encode(['code' => -1, 'msg' => '代挂QQ号无效']));

    $skey = trim((string)($dg['skey'] ?? ''));
    $pskey = trim((string)($dg['pskey'] ?? ''));
    $superkey = trim((string)($dg['superkey'] ?? ''));
    $cookie = (string)($dg['cookie'] ?? '');
    if ($skey === '') $skey = qzone_extract_cookie_value($cookie, 'skey');
    if ($pskey === '') $pskey = qzone_extract_cookie_value($cookie, 'p_skey');
    if ($superkey === '') $superkey = qzone_extract_cookie_value($cookie, 'superkey');

    $nickname = trim((string)($dg['qq_name'] ?? ($dg['nickname'] ?? '')));
    $gtk = '';
    $qzonetoken = '';
    $loginStatus = 1;
    if ($skey !== '' && $pskey !== '') {
        $gtk = QzoneService::qzoneGetGTK($pskey);
        $qzonetoken = QzoneService::qzoneGetQzonetoken($qq, $skey, $pskey);
        $loginStatus = 0;
    }

    $qqDb = daddslashes($qq);
    $nicknameDb = daddslashes($nickname);
    $skeyDb = daddslashes($skey);
    $pskeyDb = daddslashes($pskey);
    $superkeyDb = daddslashes($superkey);
    $gtkDb = daddslashes($gtk);
    $qzonetokenDb = daddslashes($qzonetoken);

    $existId = intval($DB->getColumn("SELECT id FROM " . DBQZ . "qzone_qq WHERE qq='{$qqDb}' LIMIT 1"));
    if ($existId > 0) {
        $DB->exec("UPDATE " . DBQZ . "qzone_qq SET user_id='{$user_id}', nickname='{$nicknameDb}', skey='{$skeyDb}', pskey='{$pskeyDb}', superkey='{$superkeyDb}', gtk='{$gtkDb}', qzonetoken='{$qzonetokenDb}', login_status='{$loginStatus}', login_time=NOW() WHERE id='{$existId}'");
        qzone_ensure_config_exists($existId);
        $msg = ($loginStatus === 0) ? '已从代挂版同步到秒赞版' : '已从代挂版添加到秒赞版（未获取到Cookie，需在秒赞版更新状态）';
        exit(json_encode(['code' => 0, 'msg' => $msg]));
    }

    $DB->exec("INSERT INTO " . DBQZ . "qzone_qq (user_id, qq, nickname, skey, pskey, superkey, gtk, qzonetoken, login_status, login_time, vip_time) VALUES ('{$user_id}', '{$qqDb}', '{$nicknameDb}', '{$skeyDb}', '{$pskeyDb}', '{$superkeyDb}', '{$gtkDb}', '{$qzonetokenDb}', '{$loginStatus}', NOW(), NOW())");
    $newId = intval($DB->lastInsertId());
    qzone_ensure_config_exists($newId);
    $msg = ($loginStatus === 0) ? '已从代挂版添加到秒赞版' : '已从代挂版添加到秒赞版（未获取到Cookie，需在秒赞版更新状态）';
    exit(json_encode(['code' => 0, 'msg' => $msg]));
break;

case 'import_ck':
    $qqInput = isset($_POST['qq']) ? trim($_POST['qq']) : '';
    $cookie = isset($_POST['cookie']) ? trim($_POST['cookie']) : '';

    if ($cookie === '') {
        exit(json_encode(['code' => -1, 'msg' => 'Cookie不能为空']));
    }

    $cookieQq = '';
    foreach (['uin', 'p_uin', 'pt2gguin'] as $key) {
        $v = qzone_extract_cookie_value($cookie, $key);
        if ($v !== '' && preg_match('/^o?(\d{5,11})$/', trim($v), $mm)) {
            $cookieQq = $mm[1];
            break;
        }
    }

    if ($qqInput !== '') {
        if (!preg_match('/^\d{5,11}$/', $qqInput)) {
            exit(json_encode(['code' => -1, 'msg' => 'QQ号格式不正确']));
        }
        if ($cookieQq !== '' && $cookieQq !== $qqInput) {
            exit(json_encode(['code' => -1, 'msg' => 'QQ号与Cookie不匹配']));
        }
        $qq = $qqInput;
    } else {
        if ($cookieQq === '') {
            exit(json_encode(['code' => -1, 'msg' => 'Cookie中未找到QQ号(uin/p_uin/pt2gguin)']));
        }
        $qq = $cookieQq;
    }

    // 解析Cookie
    $skey = qzone_extract_cookie_value($cookie, 'skey');
    $pskey = qzone_extract_cookie_value($cookie, 'p_skey');

    if (empty($skey) || empty($pskey)) {
        exit(json_encode(['code' => -1, 'msg' => 'Cookie缺少必要参数(skey/p_skey)']));
    }

    $gtk = QzoneService::qzoneGetGTK($skey);

    $nickname = '';

    $nicknameApis = [
        [
            'url' => 'https://r.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?g_tk=' . $gtk . '&uins=' . $qq,
            'parse' => function($response) {
                if (preg_match('/portraitCall[Bb]ack\(\s*(.+)\s*\)\s*$/s', $response, $jsonMatch)) {
                    $jsonStr = $jsonMatch[1];
                    $data = json_decode($jsonStr, true);
                    if ($data && is_array($data)) {
                        foreach ($data as $qq => $info) {
                            if (is_array($info) && count($info) >= 7) {
                                $nick = $info[6];
                                if (!empty($nick) && is_string($nick)) {
                                    return $nick;
                                }
                            }
                        }
                    }
                }
                return '';
            }
        ]
    ];

    $getNicknameHeaders = [
        'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Referer: https://qzone.qq.com/',
        'Cookie: skey=' . $skey . '; p_skey=' . $pskey . '; uin=o' . $qq
    ];

    $nicknameRes = '';
    $apiIndex = 0;
    foreach ($nicknameApis as $index => $apiConfig) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $apiConfig['url']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $getNicknameHeaders);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
        curl_setopt($ch, CURLOPT_ENCODING, '');
        $nicknameRes = curl_exec($ch);
        curl_close($ch);

        if (!empty($nicknameRes)) {
            $nicknameResUtf8 = mb_convert_encoding($nicknameRes, 'UTF-8', 'GBK');
            if (empty($nicknameResUtf8)) {
                $nicknameResUtf8 = $nicknameRes;
            }

            $nickname = $apiConfig['parse']($nicknameResUtf8);
            if (!empty($nickname)) {
                break;
            }
        }
    }

    // 检查是否已存在
    $qqDb = daddslashes($qq);
    $exists = $DB->getRow("SELECT id, nickname as old_nickname FROM " . DBQZ . "qzone_qq WHERE qq='{$qqDb}'");
    $old_nickname = $exists['old_nickname'] ?? '';

    // 如果获取新昵称为空，但数据库有旧昵称，保持旧昵称
    if (empty($nickname) && !empty($old_nickname)) {
        $nickname = $old_nickname;
    }

    if ($exists) {
        // 更新
        $nickname = daddslashes($nickname);
        $skeyDb = daddslashes($skey);
        $pskeyDb = daddslashes($pskey);
        $gtkDb = daddslashes($gtk);
        $DB->exec("UPDATE " . DBQZ . "qzone_qq SET skey='{$skeyDb}', pskey='{$pskeyDb}', superkey='', gtk='{$gtkDb}', qzonetoken='', nickname='{$nickname}', login_status=0, login_time=NOW() WHERE qq='{$qqDb}'");
        
        $response = json_encode(['code' => 0, 'msg' => 'CK更新成功', 'qq' => $qq, 'nickname' => $nickname]);
        
        if ($response === false) {
            exit(json_encode(['code' => -1, 'msg' => 'JSON编码失败: ' . json_last_error_msg()]));
        }
        
        echo $response;
        
        while (ob_get_level() > 0) {
            ob_end_flush();
        }
        
        if (function_exists('fastcgi_finish_request')) {
            fastcgi_finish_request();
        }
        
        exit;
    } else {
        // 新增
        $nickname = daddslashes($nickname);
        $skeyDb = daddslashes($skey);
        $pskeyDb = daddslashes($pskey);
        $gtkDb = daddslashes($gtk);
        $DB->exec("INSERT INTO " . DBQZ . "qzone_qq (qq, skey, pskey, superkey, gtk, qzonetoken, nickname, user_id, login_status, login_time, vip_time) VALUES ('{$qqDb}', '{$skeyDb}', '{$pskeyDb}', '', '{$gtkDb}', '', '{$nickname}', '{$user_id}', 0, NOW(), NOW())");
        $new_id = $DB->lastInsertId();
        $DB->exec("INSERT INTO " . DBQZ . "qzone_config (qid) VALUES ('{$new_id}')");
        
        $response = json_encode(['code' => 0, 'msg' => 'CK导入成功', 'qq' => $qq, 'nickname' => $nickname]);
        
        if ($response === false) {
            exit(json_encode(['code' => -1, 'msg' => 'JSON编码失败: ' . json_last_error_msg()]));
        }
        
        echo $response;
        
        while (ob_get_level() > 0) {
            ob_end_flush();
        }
        
        if (function_exists('fastcgi_finish_request')) {
            fastcgi_finish_request();
        }
        
        exit;
    }
break;

case 'pwd_login':
    exit(json_encode(['code' => -1, 'msg' => '接口已下线，请使用 init_pwd_web/finalize_pwd_web']));
break;

case 'get_qrcode':
    $node_index = isset($_GET['node']) ? intval($_GET['node']) : 0;
    if ($node_index > 0 && isset($qzone_nodes[$node_index - 1])) {
        $node = $qzone_nodes[$node_index - 1];
        $node_type = $node['type'] ?? 'url';

        if ($node_type === 'socks5') {
            $proxy = [
                'type' => 'socks5',
                'host' => $node['socks5_host'],
                'port' => $node['socks5_port'],
                'user' => $node['socks5_user'] ?? '',
                'pass' => $node['socks5_pass'] ?? ''
            ];
            $login = new QzoneLoginService($proxy);
            $result = $login->getqrpic();
            if ($result['saveOK'] == 0) {
                exit(json_encode(['code' => 0, 'qrsig' => $result['qrsig'], 'image' => $result['image']]));
            }
            exit(json_encode(['code' => -1, 'msg' => $result['msg'] ?? '获取二维码失败']));
        }

        $node_url = rtrim($node['url'] ?? '', '/');
        $url = (strpos($node_url, '?') !== false ? $node_url . '&' : $node_url . '?') . 'act=get_qrcode';
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $body = curl_exec($ch);
        curl_close($ch);
        if ($body !== false) {
            header('Content-Type: application/json; charset=UTF-8');
            exit($body);
        }
        exit(json_encode(['code' => -1, 'msg' => '节点请求失败，请换节点或使用主站']));
    }
    $login = new QzoneLoginService();
    $result = $login->getqrpic();
    if ($result['saveOK'] == 0) {
        exit(json_encode(['code' => 0, 'qrsig' => $result['qrsig'], 'image' => $result['image']]));
    }
    exit(json_encode(['code' => -1, 'msg' => $result['msg'] ?? '获取二维码失败']));
break;

case 'check_qrlogin':
    $qrsig = daddslashes($_POST['qrsig'] ?? '');
    if (!$qrsig) exit(json_encode(['code' => -1, 'msg' => '参数错误']));
    $update_qid = intval($_POST['update_qid'] ?? 0);
    $node_index = isset($_POST['node']) ? intval($_POST['node']) : 0;
    if ($node_index > 0 && isset($qzone_nodes[$node_index - 1])) {
        $node = $qzone_nodes[$node_index - 1];
        $node_type = $node['type'] ?? 'url';

        if ($node_type === 'socks5') {
            $proxy = [
                'type' => 'socks5',
                'host' => $node['socks5_host'],
                'port' => $node['socks5_port'],
                'user' => $node['socks5_user'] ?? '',
                'pass' => $node['socks5_pass'] ?? ''
            ];
            $login = new QzoneLoginService($proxy);
            $result = $login->qrlogin($qrsig);

            if ($result['saveOK'] == 0) {
                $qq = $result['uin'];
                $skey = $result['skey'];
                $pskey = $result['pskey'];
                $superkey = $result['superkey'];
                $nickname = $result['nickname'];

                if (empty($qq) || !is_numeric($qq) || $qq == '0') {
                    exit(json_encode(['code' => -1, 'msg' => 'QQ号无效']));
                }

                $gtk = QzoneService::qzoneGetGTK($pskey);
                $qzonetoken = QzoneService::qzoneGetQzonetoken($qq, $skey, $pskey);
                $skey = daddslashes($skey);
                $pskey = daddslashes($pskey);
                $superkey = daddslashes($superkey);
                $gtk = daddslashes($gtk);
                $qzonetoken = daddslashes($qzonetoken);
                $nickname = daddslashes($nickname);
                $qq = daddslashes($qq);

                if ($update_qid > 0) {
                    $target = qzone_validate_qid_ownership($update_qid, $user_id);
                    if (isset($target['error'])) exit(json_encode(['code' => -1, 'msg' => $target['error']]));
                    if ((string)$target['qq'] !== (string)$qq) exit(json_encode(['code' => -2, 'msg' => '扫码QQ不匹配，请使用QQ '.$target['qq'].' 重新扫码']));
                    $DB->exec("UPDATE " . DBQZ . "qzone_qq SET skey='{$skey}', pskey='{$pskey}', superkey='{$superkey}', gtk='{$gtk}', qzonetoken='{$qzonetoken}', nickname='{$nickname}', login_status=0, login_time=NOW() WHERE id='{$update_qid}'");
                    exit(json_encode(['code' => 0, 'msg' => '状态更新成功']));
                }
                $existId = $DB->getColumn("SELECT id FROM " . DBQZ . "qzone_qq WHERE qq='{$qq}'");
                if ($existId) {
                    $DB->exec("UPDATE " . DBQZ . "qzone_qq SET user_id='{$user_id}', skey='{$skey}', pskey='{$pskey}', superkey='{$superkey}', gtk='{$gtk}', qzonetoken='{$qzonetoken}', nickname='{$nickname}', login_status=0, login_time=NOW() WHERE id='{$existId}'");
                } else {
                    $DB->exec("INSERT INTO " . DBQZ . "qzone_qq (user_id, qq, nickname, skey, pskey, superkey, gtk, qzonetoken, login_status, login_time, vip_time) VALUES ('{$user_id}', '{$qq}', '{$nickname}', '{$skey}', '{$pskey}', '{$superkey}', '{$gtk}', '{$qzonetoken}', 0, NOW(), NOW())");
                }
                exit(json_encode(['code' => 0, 'msg' => '登录成功']));
            } elseif ($result['saveOK'] == 1) {
                exit(json_encode(['code' => 1, 'msg' => '二维码已过期']));
            } elseif ($result['saveOK'] == 2) {
                exit(json_encode(['code' => 2, 'msg' => '等待扫码']));
            } elseif ($result['saveOK'] == 3) {
                exit(json_encode(['code' => 3, 'msg' => '等待确认']));
            }
            exit(json_encode(['code' => -1, 'msg' => $result['msg'] ?? '登录失败']));
        }

        $node_url = rtrim($node['url'] ?? '', '/');
        $post = ['qrsig' => $qrsig];
        $url = (strpos($node_url, '?') !== false ? $node_url . '&' : $node_url . '?') . 'act=check_qrlogin';
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 20);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $body = curl_exec($ch);
        curl_close($ch);
        if ($body !== false) {
            $nodeRes = json_decode($body, true);
            if (is_array($nodeRes) && isset($nodeRes['code']) && $nodeRes['code'] == 0 && !empty($nodeRes['uin'])) {
                $qq = $nodeRes['uin'];
                $skey = $nodeRes['skey'] ?? '';
                $pskey = $nodeRes['pskey'] ?? '';
                $superkey = $nodeRes['superkey'] ?? '';
                $nickname = $nodeRes['nickname'] ?? '';
                $gtk = QzoneService::qzoneGetGTK($pskey);
                $qzonetoken = QzoneService::qzoneGetQzonetoken($qq, $skey, $pskey);
                $skey = daddslashes($skey);
                $pskey = daddslashes($pskey);
                $superkey = daddslashes($superkey);
                $gtk = daddslashes($gtk);
                $qzonetoken = daddslashes($qzonetoken);
                $nickname = daddslashes($nickname);
                $qq = daddslashes($qq);
                if ($update_qid > 0) {
                    $target = qzone_validate_qid_ownership($update_qid, $user_id);
                    if (isset($target['error'])) exit(json_encode(['code' => -1, 'msg' => $target['error']]));
                    if ((string)$target['qq'] !== (string)$qq) exit(json_encode(['code' => -2, 'msg' => '扫码QQ不匹配，请使用QQ '.$target['qq'].' 重新扫码']));
                    $DB->exec("UPDATE " . DBQZ . "qzone_qq SET skey='{$skey}', pskey='{$pskey}', superkey='{$superkey}', gtk='{$gtk}', qzonetoken='{$qzonetoken}', nickname='{$nickname}', login_status=0, login_time=NOW() WHERE id='{$update_qid}'");
                    exit(json_encode(['code' => 0, 'msg' => '状态更新成功']));
                }
                $existId = $DB->getColumn("SELECT id FROM " . DBQZ . "qzone_qq WHERE qq='{$qq}'");
                if ($existId) {
                    $DB->exec("UPDATE " . DBQZ . "qzone_qq SET user_id='{$user_id}', skey='{$skey}', pskey='{$pskey}', superkey='{$superkey}', gtk='{$gtk}', qzonetoken='{$qzonetoken}', nickname='{$nickname}', login_status=0, login_time=NOW() WHERE id='{$existId}'");
                } else {
                    $DB->exec("INSERT INTO " . DBQZ . "qzone_qq (user_id, qq, nickname, skey, pskey, superkey, gtk, qzonetoken, login_status, login_time, vip_time) VALUES ('{$user_id}', '{$qq}', '{$nickname}', '{$skey}', '{$pskey}', '{$superkey}', '{$gtk}', '{$qzonetoken}', 0, NOW(), NOW())");
                }
                exit(json_encode(['code' => 0, 'msg' => '登录成功']));
            }
            header('Content-Type: application/json; charset=UTF-8');
            exit($body);
        }
        exit(json_encode(['code' => -1, 'msg' => '节点请求失败，请换节点或使用主站']));
    }

    $login = new QzoneLoginService();
    $result = $login->qrlogin($qrsig);

    if ($result['saveOK'] == 0) {
        $qq = $result['uin'];
        $skey = $result['skey'];
        $pskey = $result['pskey'];
        $superkey = $result['superkey'];
        $nickname = $result['nickname'];

        if (empty($qq) || !is_numeric($qq) || $qq == '0') {
            exit(json_encode(['code' => -1, 'msg' => 'QQ号无效']));
        }

        $gtk = QzoneService::qzoneGetGTK($pskey);
        $qzonetoken = QzoneService::qzoneGetQzonetoken($qq, $skey, $pskey);

        if ($update_qid > 0) {
            $target = qzone_validate_qid_ownership($update_qid, $user_id);
            if (isset($target['error'])) exit(json_encode(['code' => -1, 'msg' => $target['error']]));
            if ((string)$target['qq'] !== (string)$qq) {
                exit(json_encode(['code' => -2, 'msg' => '扫码QQ不匹配，请使用QQ '.$target['qq'].' 重新扫码']));
            }
            $DB->exec("UPDATE " . DBQZ . "qzone_qq SET skey='{$skey}', pskey='{$pskey}', superkey='{$superkey}', gtk='{$gtk}', qzonetoken='{$qzonetoken}', nickname='{$nickname}', login_status=0, login_time=NOW() WHERE id='{$update_qid}'");
            exit(json_encode(['code' => 0, 'msg' => '状态更新成功']));
        }

        $existId = $DB->getColumn("SELECT id FROM " . DBQZ . "qzone_qq WHERE qq='{$qq}'");
        if ($existId) {
            $DB->exec("UPDATE " . DBQZ . "qzone_qq SET user_id='{$user_id}', skey='{$skey}', pskey='{$pskey}', superkey='{$superkey}', gtk='{$gtk}', qzonetoken='{$qzonetoken}', nickname='{$nickname}', login_status=0, login_time=NOW() WHERE id='{$existId}'");
        } else {
            $DB->exec("INSERT INTO " . DBQZ . "qzone_qq (user_id, qq, nickname, skey, pskey, superkey, gtk, qzonetoken, login_status, login_time, vip_time) VALUES ('{$user_id}', '{$qq}', '{$nickname}', '{$skey}', '{$pskey}', '{$superkey}', '{$gtk}', '{$qzonetoken}', 0, NOW(), NOW())");
        }
        exit(json_encode(['code' => 0, 'msg' => '登录成功']));
    } elseif ($result['saveOK'] == 1) {
        exit(json_encode(['code' => 1, 'msg' => '二维码已过期']));
    } elseif ($result['saveOK'] == 2) {
        exit(json_encode(['code' => 2, 'msg' => '等待扫码']));
    } elseif ($result['saveOK'] == 3) {
        exit(json_encode(['code' => 3, 'msg' => '等待确认']));
    }
    exit(json_encode(['code' => -1, 'msg' => $result['msg'] ?? '登录失败']));
break;

case 'get_config':
    $qid = intval($_POST['qid'] ?? 0);
    if (!$qid) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $qq = qzone_validate_qid_ownership($qid, $user_id);
    if (isset($qq['error'])) exit(json_encode(['code' => -1, 'msg' => $qq['error']]));

    qzone_ensure_config_exists($qid);
    $config = $DB->getRow("SELECT * FROM " . DBQZ . "qzone_config WHERE qid='{$qid}'") ?: [];
    $is_vip = $qq['vip_time'] && strtotime($qq['vip_time']) > time();

    exit(json_encode(['code' => 1, 'data' => $config, 'is_vip' => $is_vip]));
break;

case 'save_user_config':
    $qid = intval($_POST['qid'] ?? 0);
    if (!$qid) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $qq = qzone_validate_qid_ownership($qid, $user_id);
    if (isset($qq['error'])) exit(json_encode(['code' => -1, 'msg' => $qq['error']]));

    $isVip = strtotime($qq['vip_time']) > time();
    qzone_ensure_config_exists($qid);
    $configCols = getConfigColumns();
    if (empty($configCols['cloud_auto_update_ck'])) {
        $DB->exec("ALTER TABLE " . DBQZ . "qzone_config ADD COLUMN `cloud_auto_update_ck` tinyint(1) NOT NULL DEFAULT 0 COMMENT '云端自动更新CK开关' AFTER `invalid_remind_switch`");
        $configCols = getConfigColumns();
    }
    $requiredSwitchCols = [
        'zdfss_switch' => "`zdfss_switch` tinyint(1) NOT NULL DEFAULT 0 COMMENT '自动发说说开关'",
        'zdfss_delete_prev' => "`zdfss_delete_prev` tinyint(1) NOT NULL DEFAULT 0 COMMENT '发说说前删除上一条'",
        'clear_ss_switch' => "`clear_ss_switch` tinyint(1) NOT NULL DEFAULT 0 COMMENT '自动清空说说开关'",
        'clear_ly_switch' => "`clear_ly_switch` tinyint(1) NOT NULL DEFAULT 0 COMMENT '自动清空留言开关'"
    ];
    foreach ($requiredSwitchCols as $col => $sqlDef) {
        if (empty($configCols[$col])) {
            $DB->exec("ALTER TABLE " . DBQZ . "qzone_config ADD COLUMN {$sqlDef}");
        }
    }
    $configCols = getConfigColumns();

    if (isset($_POST['zdfss_cycle_num']) || isset($_POST['zdfss_cycle_unit'])) {
        $num = isset($_POST['zdfss_cycle_num']) ? max(1, intval($_POST['zdfss_cycle_num'])) : -1;
        $unit = isset($_POST['zdfss_cycle_unit']) ? $_POST['zdfss_cycle_unit'] : '';
        
        // 如果只传了其中一个，从数据库读取另一个
        if ($num === -1 || $unit === '') {
            $old_config = $DB->getRow("SELECT zdfss_exec_cycle FROM " . DBQZ . "qzone_config WHERE qid='{$qid}'");
            $old_seconds = intval($old_config['zdfss_exec_cycle'] ?? 60);
            
            if ($num === -1) {
                // 根据旧的总秒数和新单位（如果有）或旧单位推算旧数值
                // 这里逻辑稍微复杂，最稳妥的是前端保证两个一起传，或者后端根据秒数反推
                if ($unit === 'day') $num = ceil($old_seconds / 86400);
                elseif ($unit === 'hour') $num = ceil($old_seconds / 3600);
                else $num = ceil($old_seconds / 60);
            }
            if ($unit === '') {
                // 根据旧秒数推算单位
                if ($old_seconds % 86400 === 0) $unit = 'day';
                elseif ($old_seconds % 3600 === 0) $unit = 'hour';
                else $unit = 'minute';
            }
        }
        
        $_POST['zdfss_exec_cycle'] = $num * ($unit === 'day' ? 86400 : ($unit === 'hour' ? 3600 : 60));
        $_POST['zdfss_cycle'] = $num * ($unit === 'day' ? 1440 : ($unit === 'hour' ? 60 : 1)); // 分钟
    }

    if (isset($_POST['sign_cycle_num']) || isset($_POST['sign_cycle_unit'])) {
        $num = isset($_POST['sign_cycle_num']) ? max(1, intval($_POST['sign_cycle_num'])) : -1;
        $unit = isset($_POST['sign_cycle_unit']) ? $_POST['sign_cycle_unit'] : '';
        
        if ($num === -1 || $unit === '') {
            $old_config = $DB->getRow("SELECT sign_cycle FROM " . DBQZ . "qzone_config WHERE qid='{$qid}'");
            $old_minutes = intval($old_config['sign_cycle'] ?? 60);
            
            if ($num === -1) {
                if ($unit === 'day') $num = ceil($old_minutes / 1440);
                elseif ($unit === 'hour') $num = ceil($old_minutes / 60);
                else $num = $old_minutes;
            }
            if ($unit === '') {
                if ($old_minutes % 1440 === 0) $unit = 'day';
                elseif ($old_minutes % 60 === 0) $unit = 'hour';
                else $unit = 'minute';
            }
        }
        
        $_POST['sign_cycle'] = $num * ($unit === 'day' ? 1440 : ($unit === 'hour' ? 60 : 1));
    }

    if (isset($_POST['monitor_cycle_seconds'])) {
        $sec = max(20, intval($_POST['monitor_cycle_seconds']));
        if (intval($conf['qzone_monitor_cycle_vip'] ?? 0) === 1 && !$isVip) {
            $sec = max(20, max(1, intval($conf['qzone_free_monitor_cycle'] ?? 1)) * 60);
        }
        $_POST['monitor_cycle_seconds'] = $sec;
    }

    $fields = [
        'invalid_remind_switch', 'cloud_auto_update_ck', 'monitor_cycle_seconds',
        'ssmz_switch', 'ssmz_whitelist', 'ssmz_blacklist', 'ssmz_cycle', 'ssmz_hourly_max',
        'ssmp_switch', 'ssmp_whitelist', 'ssmp_blacklist', 'ssmp_comment', 'ssmp_pic_url', 'ssmp_cycle', 'ssmp_hourly_max',
        'zdfss_switch', 'zdfss_whitelist', 'zdfss_content', 'zdfss_pic_url', 'zdfss_exec_cycle', 'zdfss_delete_prev',
        'zfss_switch', 'zfss_content', 'zfss_forward_list',
        'sign_switch', 'sign_cycle', 'sign_content',
        'clear_ss_switch', 'clear_ly_switch'
    ];

    foreach ($fields as $field) {
        if (!isset($_POST[$field])) continue;

        $value = $_POST[$field];
        $targetField = $field;

        switch ($field) {
            case 'monitor_cycle_seconds':
                $freeCycle = max(1, intval($conf['qzone_free_monitor_cycle'] ?? 1));
                if (intval($conf['qzone_monitor_cycle_vip'] ?? 0) === 1 && !$isVip) {
                    $value = max(20, $freeCycle * 60);
                }
                $value = max(20, intval($value));
                break;
            case 'ssmz_hourly_max':
                if (intval($conf['qzone_ssmz_hourly_vip'] ?? 0) === 1 && !$isVip) {
                    $value = max(0, intval($conf['qzone_free_hourly_ssmz'] ?? 0));
                }
                $value = max(0, intval($value));
                break;
            case 'ssmp_hourly_max':
                if (intval($conf['qzone_ssmp_hourly_vip'] ?? 0) === 1 && !$isVip) {
                    $value = max(0, intval($conf['qzone_free_hourly_ssmp'] ?? 0));
                }
                $value = max(0, intval($value));
                break;
            case 'cloud_auto_update_ck':
                if (intval($conf['qzone_cloud_cookie'] ?? 0) === 1 && !$isVip) {
                    $value = 0;
                } else {
                    $value = intval($value) === 1 ? 1 : 0;
                }
                break;
            case 'zdfss_delete_prev':
                if (intval($conf['qzone_zdfss_delete_vip'] ?? 1) === 1 && !$isVip) {
                    $value = 0;
                } else {
                    $value = intval($value) === 1 ? 1 : 0;
                }
                break;
            default:
                $value = daddslashes($value);
        }

        if ($field === 'zdfss_cycle' && empty($configCols['zdfss_cycle']) && !empty($configCols['zdfss_exec_cycle'])) {
            $targetField = 'zdfss_exec_cycle';
        } elseif ($field === 'zfss_whitelist' && empty($configCols['zfss_whitelist']) && !empty($configCols['zfss_forward_list'])) {
            $targetField = 'zfss_forward_list';
        } elseif ($field === 'ssmz_cycle' && empty($configCols['ssmz_cycle']) && !empty($configCols['ssmz_exec_cycle'])) {
            $targetField = 'ssmz_exec_cycle';
        } elseif ($field === 'ssmp_cycle' && empty($configCols['ssmp_cycle']) && !empty($configCols['ssmp_exec_cycle'])) {
            $targetField = 'ssmp_exec_cycle';
        } elseif ($field === 'sign_cycle') {
            $value = max(1, intval($value));
        }

        if (!empty($configCols[$targetField])) {
            $DB->exec("UPDATE " . DBQZ . "qzone_config SET `{$targetField}`='{$value}' WHERE qid='{$qid}'");
        }
    }

    exit(json_encode(['code' => 1, 'msg' => '保存成功']));
break;

case 'preview_content':
    $content = $_POST['content'] ?? '';
    if (empty($content)) exit(json_encode(['code' => -1, 'msg' => '内容为空']));
    require_once dirname(__DIR__) . '/includes/lib/qzone/QzoneHelper.php';
    $result = QzoneHelper::parseContent($content);
    $result = replace_text_variable($result);
    exit(json_encode(['code' => 1, 'data' => $result]));
break;

case 'get_user_log':
    $qid = intval($_POST['qid'] ?? 0);
    if (!$qid) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $qq = qzone_validate_qid_ownership($qid, $user_id);
    if (isset($qq['error'])) exit(json_encode(['code' => -1, 'msg' => $qq['error']]));

    $type = daddslashes($_POST['type'] ?? '');
    $typeFilter = $type ? " AND type='{$type}'" : '';

    $logTable = '';
    foreach ([DBQZ . "qzone_log", "bot_qzone_log", "pre_qzone_log"] as $tb) {
        if ($DB->getColumn("SHOW TABLES LIKE '{$tb}'")) {
            $logTable = $tb;
            break;
        }
    }
    if (!$logTable) exit(json_encode(['code' => -1, 'msg' => '日志表不存在']));

    $logs = $DB->getAll("SELECT * FROM {$logTable} WHERE qid='{$qid}' {$typeFilter} ORDER BY id DESC LIMIT 100") ?: [];
    $countQid = intval($DB->getColumn("SELECT COUNT(*) FROM {$logTable} WHERE qid='{$qid}'"));
    $matchedQids = [$qid];

    if (empty($logs) && !empty($qq['qq'])) {
        $sameRows = $DB->getAll("SELECT id FROM " . DBQZ . "qzone_qq WHERE qq='" . daddslashes($qq['qq']) . "'");
        $qidArr = array_filter(array_unique(array_column($sameRows, 'id')));
        if (!empty($qidArr)) {
            $matchedQids = array_values($qidArr);
            $logs = $DB->getAll("SELECT * FROM {$logTable} WHERE qid IN (" . implode(',', $qidArr) . ") {$typeFilter} ORDER BY id DESC LIMIT 100") ?: [];
        }
    }

    if (empty($logs)) {
        $cfg = $DB->getRow("SELECT last_monitor_time FROM " . DBQZ . "qzone_config WHERE qid='{$qid}'");
        $acc = $DB->getRow("SELECT login_status,login_time FROM " . DBQZ . "qzone_qq WHERE id='{$qid}'");
        if (!empty($cfg['last_monitor_time'])) {
            $monitorMsg = '最近监控时间：' . $cfg['last_monitor_time'];
            if (isset($acc['login_status'])) {
                $monitorMsg .= '，当前状态：' . (intval($acc['login_status']) === 0 ? '在线' : '离线');
            }
            $logs[] = [
                'id' => 0,
                'qid' => $qid,
                'type' => 'monitor',
                'content' => $monitorMsg,
                'status' => 1,
                'create_time' => $cfg['last_monitor_time']
            ];
        }
    }

    $meta = [
        'log_table' => $logTable,
        'count_qid' => $countQid,
        'count_returned' => count($logs),
        'matched_qids' => $matchedQids
    ];
    exit(json_encode(['code' => 1, 'data' => $logs, 'meta' => $meta]));
break;

case 'clear_user_log':
    $qid = intval($_POST['qid'] ?? 0);
    if (!$qid) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $qq = qzone_validate_qid_ownership($qid, $user_id);
    if (isset($qq['error'])) exit(json_encode(['code' => -1, 'msg' => $qq['error']]));

    foreach ([DBQZ . "qzone_log", "bot_qzone_log", "pre_qzone_log"] as $tb) {
        if ($DB->getColumn("SHOW TABLES LIKE '{$tb}'")) {
            $DB->exec("DELETE FROM `{$tb}` WHERE qid='{$qid}'");
            break;
        }
    }
    exit(json_encode(['code' => 1, 'msg' => '日志已清空']));
break;

case 'refresh_status':
    $qid = intval($_POST['qid'] ?? 0);
    if (!$qid) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $qq = qzone_validate_qid_ownership($qid, $user_id);
    if (isset($qq['error'])) exit(json_encode(['code' => -1, 'msg' => $qq['error']]));

    $login_status = 1;
    try {
        $qzone = new QzoneService($qq['qq'], $qq['skey'], $qq['pskey'], $qq['gtk']);
        if ($qzone->checkLogin()) $login_status = 0;
    } catch (Exception $e) {}

    $DB->exec("UPDATE " . DBQZ . "qzone_qq SET login_status='{$login_status}' WHERE id='{$qid}'");
    exit(json_encode(['code' => 1, 'msg' => '状态已更新', 'login_status' => $login_status]));
break;

case 'delete_ck':
    $qid = intval($_POST['qid'] ?? 0);
    if (!$qid) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $qq = qzone_validate_qid_ownership($qid, $user_id);
    if (isset($qq['error'])) exit(json_encode(['code' => -1, 'msg' => $qq['error']]));

    $DB->exec("UPDATE " . DBQZ . "qzone_qq SET skey='', pskey='', superkey='', gtk='', qzonetoken='', login_status=1 WHERE id='{$qid}'");
    exit(json_encode(['code' => 1, 'msg' => 'Cookie已删除']));
break;

case 'delete_user_qq':
    $qid = intval($_POST['qid'] ?? 0);
    if (!$qid) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $qq = qzone_validate_qid_ownership($qid, $user_id);
    if (isset($qq['error'])) exit(json_encode(['code' => -1, 'msg' => $qq['error']]));

    $DB->exec("DELETE FROM " . DBQZ . "qzone_qq WHERE id='{$qid}'");
    $DB->exec("DELETE FROM " . DBQZ . "qzone_config WHERE qid='{$qid}'");
    $DB->exec("DELETE FROM " . DBQZ . "qzone_log WHERE qid='{$qid}'");
    exit(json_encode(['code' => 1, 'msg' => '删除成功']));
break;

case 'get_user_qq_list':
    $page = intval($_POST['page'] ?? 1);
    $pagesize = intval($_POST['pagesize'] ?? 10);
    $offset = ($page - 1) * $pagesize;

    $total = $DB->getColumn("SELECT COUNT(*) FROM " . DBQZ . "qzone_qq WHERE user_id='{$user_id}'");
    $list = $DB->getAll("SELECT * FROM " . DBQZ . "qzone_qq WHERE user_id='{$user_id}' ORDER BY id DESC LIMIT {$offset}, {$pagesize}");

    exit(json_encode(['code' => 1, 'data' => $list ?: [], 'total' => intval($total), 'page' => $page, 'pages' => ceil($total / $pagesize)]));
break;

case 'upload_image':
    if (!isset($_FILES['file']) || intval($_FILES['file']['error'] ?? -1) !== 0) {
        exit(json_encode(['code' => -1, 'msg' => '请选择图片']));
    }
    $file = $_FILES['file'];
    if (empty($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) {
        exit(json_encode(['code' => -1, 'msg' => '无效的上传文件']));
    }
    if ($file['size'] <= 0 || $file['size'] > 5 * 1024 * 1024) {
        exit(json_encode(['code' => -1, 'msg' => '图片大小需在5MB以内']));
    }

    $ext = strtolower(pathinfo($file['name'] ?? '', PATHINFO_EXTENSION));
    if (!in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'], true)) {
        exit(json_encode(['code' => -1, 'msg' => '仅支持jpg/png/gif/webp']));
    }

    $uploadDir = ROOT . 'assets/img/qzon/';
    if (!is_dir($uploadDir) && !mkdir($uploadDir, 0755, true)) {
        exit(json_encode(['code' => -1, 'msg' => '创建目录失败']));
    }

    $filename = date('YmdHis') . '_' . substr(md5_file($file['tmp_name']) . md5(uniqid('', true)), 0, 16) . '.' . $ext;
    if (!move_uploaded_file($file['tmp_name'], $uploadDir . $filename)) {
        exit(json_encode(['code' => -1, 'msg' => '保存失败，请检查目录权限']));
    }

    exit(json_encode(['code' => 1, 'msg' => '上传成功', 'url' => '/assets/img/qzon/' . $filename]));
break;

case 'get_cloud_cookie':
    $qid = intval($_GET['qid'] ?? 0);
    if (!$qid) exit(json_encode(['code' => -1, 'msg' => '参数错误']));

    $qq = $DB->getRow("SELECT * FROM " . DBQZ . "qzone_qq WHERE id='{$qid}' AND user_id='{$user_id}'");
    if (!$qq) exit(json_encode(['code' => -1, 'msg' => 'QQ不存在']));
    $isVip = $qq['vip_time'] && strtotime($qq['vip_time']) > time();

    if (($conf['qzone_cloud_update_status'] ?? '1') != '1') exit(json_encode(['code' => -1, 'msg' => '从云端版更新状态功能未开启']));
    if (($conf['qzone_cloud_cookie'] ?? '0') == '1' && !$isVip) exit(json_encode(['code' => -1, 'msg' => '该功能需VIP']));

    $cloudQueryQQ = daddslashes($qq['qq']);
    $cloudEnabled = (($conf['cloud_enabled'] ?? '1') == '1');
    $dgEnabled = (($conf['dg_open'] ?? '0') == '1');
    if (!$cloudEnabled && !$dgEnabled) exit(json_encode(['code' => -1, 'msg' => '云端/代挂功能未开启']));
    $srcType = 'cloud';
    $srcName = '云端版';
    $cloudQQ = $cloudEnabled ? $DB->getRow("SELECT id,cityid,login_zt FROM pre_qq WHERE qq='{$cloudQueryQQ}' AND zid='{$user_id}' LIMIT 1") : null;
    $dgQQ = null;
    if ($dgEnabled) {
        $dgQQ = $DB->getRow("SELECT id,cityid,login_zt FROM pre_dg_qq WHERE qq='{$cloudQueryQQ}' AND zid='{$user_id}' LIMIT 1");
    }
    if (!$cloudQQ && !$dgQQ) exit(json_encode(['code' => -1, 'msg' => '云端/代挂未添加该QQ']));
    if ($cloudQQ && intval($cloudQQ['login_zt']) === 1) {
    } elseif ($dgQQ && intval($dgQQ['login_zt']) === 1) {
        $cloudQQ = $dgQQ;
        $srcType = 'dg';
        $srcName = '代挂版';
    } else {
        if ($cloudQQ && $dgQQ) exit(json_encode(['code' => -1, 'msg' => '云端/代挂离线']));
        if ($cloudQQ) exit(json_encode(['code' => -1, 'msg' => '云端版离线']));
        exit(json_encode(['code' => -1, 'msg' => '代挂版离线']));
    }

    $cityid = intval($cloudQQ['cityid'] ?? 0);
    if ($cityid <= 0) exit(json_encode(['code' => -1, 'msg' => $srcName . '未绑定登录节点']));

    $login = get_login_config($cityid);
    if (!$login) exit(json_encode(['code' => -1, 'msg' => $srcName . '登录节点不存在']));
    if (isset($login['status']) && intval($login['status']) !== 1) exit(json_encode(['code' => -1, 'msg' => $srcName . '登录节点已停用']));

    $result = get_Cookies($login, $qq['qq']);

    if ($result['bool'] === true && !empty($result['Cookies'])) {
        $cookies = $result['Cookies'];
        preg_match('/(?:^|;\s*)skey=([^;]+)/i', $cookies, $skeyMatch);
        preg_match('/(?:^|;\s*)p_skey=([^;]+)/i', $cookies, $pskeyMatch);

        $skey = $skeyMatch[1] ?? '';
        $pskey = $pskeyMatch[1] ?? '';

        if (!empty($skey) && !empty($pskey)) {
            $skey = trim($skey);
            $pskey = trim($pskey);
            $gtk = QzoneService::qzoneGetGTK($pskey);
            $qzonetoken = QzoneService::qzoneGetQzonetoken($qq['qq'], $skey, $pskey);

            $skeyDb = daddslashes($skey);
            $pskeyDb = daddslashes($pskey);
            $gtkDb = daddslashes($gtk);
            $qzonetokenDb = daddslashes($qzonetoken);
            $DB->exec("UPDATE " . DBQZ . "qzone_qq SET skey='{$skeyDb}', pskey='{$pskeyDb}', gtk='{$gtkDb}', qzonetoken='{$qzonetokenDb}', login_status=0, login_time=NOW() WHERE id='{$qid}'");
            qzone_log_to_db($qid, $srcType, '从' . $srcName . '手动更新成功', 1);
            exit(json_encode(['code' => 1, 'msg' => '获取成功']));
        } else {
            exit(json_encode(['code' => 0, 'msg' => 'Cookie格式错误']));
        }
    } else {
        exit(json_encode(['code' => 0, 'msg' => $result['msg'] ?? '获取失败']));
    }
break;

default:
    exit(json_encode(['code' => -1, 'msg' => '无效操作']));
break;
}
