<?php
/**
 * V2 授权管理类
 * 处理与授权服务器的通信、token管理等
 * API地址: http://plus.a116.vip/api/v2/
 */
class AuthManager {
    private $db;
    private $api_url = 'https://plus.a116.vip/api/v2/';
    private $app_key = 'SK_b24bdfd82f5e3470a8044fdcd580cc4f';  // 软件标识
    private $client_secret = 'ShuDaXia2026SecretKey!@#$%^';  // 从开发文档获取
    private $public_key = '';
    private $token_table = 'auth_token';
    
    public function __construct($db) {
        $this->db = $db;
        $this->ensureTokenTable();
    }
    
    /**
     * 确保token表存在
     */
    private function ensureTokenTable() {
        $sql = "CREATE TABLE IF NOT EXISTS `{$this->token_table}` (
            `id` int(11) NOT NULL AUTO_INCREMENT,
            `token` varchar(512) NOT NULL,
            `refresh_token` varchar(512) DEFAULT NULL,
            `domain` varchar(255) NOT NULL,
            `expires_at` datetime NOT NULL,
            `is_trial` tinyint(1) DEFAULT 1,
            `device_id` varchar(255) DEFAULT NULL,
            `create_time` timestamp DEFAULT CURRENT_TIMESTAMP,
            `update_time` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (`id`),
            UNIQUE KEY `domain` (`domain`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
        
        $this->db->query($sql);
    }
    
    /**
     * 获取当前域名
     */
    public function getDomain() {
        return $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? '127.0.0.1';
    }
    
    /**
     * 获取设备标识（使用域名作为唯一标识）
     */
    private function getDeviceId() {
        // 使用域名作为设备标识，不统计硬件信息
        return $this->getDomain();
    }
    
    /**
     * 生成随机字符串
     */
    private function generateNonce($length = 16) {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $nonce = '';
        for ($i = 0; $i < $length; $i++) {
            $nonce .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $nonce;
    }
    
    /**
     * 发送HTTP请求到授权服务器
     */
    private function request($endpoint, $data = array()) {
        $url = $this->api_url . $endpoint;
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'Accept: application/json'
        ));
        
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            return array('code' => 500, 'message' => '请求失败: ' . $error);
        }
        
        if ($http_code != 200) {
            return array('code' => $http_code, 'message' => 'HTTP错误: ' . $http_code);
        }
        
        if (empty($response)) {
            return array('code' => 500, 'message' => '服务器返回空响应');
        }
        
        $result = json_decode($response, true);
        if (!$result) {
            return array('code' => 500, 'message' => '响应格式错误: ' . substr($response, 0, 100));
        }
        
        return $result;
    }
    
    /**
     * 初始化 - 获取RSA公钥
     */
    public function init() {
        $response = $this->request('init.php', ['app_key' => $this->app_key]);
        if ($response['code'] == 200 && isset($response['data']['public_key'])) {
            $this->public_key = $response['data']['public_key'];
            return array('code' => 200, 'message' => 'success', 'public_key' => $this->public_key);
        }
        return $response;
    }
    
    /**
     * RSA加密
     */
    private function rsaEncrypt($data) {
        if (empty($this->public_key)) {
            $init_result = $this->init();
            if ($init_result['code'] != 200) {
                return false;
            }
        }
        
        $encrypted = '';
        $result = openssl_public_encrypt($data, $encrypted, $this->public_key);
        
        if (!$result) {
            return false;
        }
        
        return base64_encode($encrypted);
    }
    
    /**
     * 获取token（使用试用授权或已激活的授权）
     * @param bool $force_verify 是否强制到服务器验证
     */
    public function getToken($force_verify = false) {
        $domain = $this->getDomain();
        
        // 先检查本地是否有token
        $stored = $this->db->get_row("SELECT * FROM `{$this->token_table}` WHERE `domain` = '{$domain}'");
        
        if (!$force_verify && $stored) {
            $expires_at = strtotime($stored['expires_at']);
            if ($expires_at > time()) {
                return array(
                    'code' => 200,
                    'message' => 'success',
                    'data' => array(
                        'token' => $stored['token'],
                        'expires_at' => $stored['expires_at'],
                        'is_trial' => $stored['is_trial'] == 1,
                        'domain' => $stored['domain']
                    )
                );
            }
        }
        
        // 本地没有有效token，尝试从授权站查询该域名是否有授权
        $remote_auth = $this->queryDomainAuth($domain);
        if ($remote_auth['code'] == 200 && isset($remote_auth['data']['token'])) {
            // 授权站有该域名的授权记录，保存到本地
            $this->saveToken(
                $remote_auth['data']['token'],
                $remote_auth['data']['refresh_token'] ?? '',
                $remote_auth['data']['expire_time'],
                $remote_auth['data']['is_trial'] ?? true
            );
            
            return array(
                'code' => 200,
                'message' => '从授权站获取授权成功',
                'data' => array(
                    'token' => $remote_auth['data']['token'],
                    'expires_at' => $remote_auth['data']['expire_time'],
                    'is_trial' => $remote_auth['data']['is_trial'] ?? true,
                    'domain' => $domain
                )
            );
        }
        
        // 授权站也没有该域名的授权，尝试申请试用
        return $this->applyTrial();
    }
    
    /**
     * 查询授权站是否有该域名的授权
     */
    public function queryDomainAuth($domain) {
        // 先初始化获取公钥
        $init_result = $this->init();
        if ($init_result['code'] != 200) {
            return $init_result;
        }
        
        $timestamp = time();
        $nonce = $this->generateNonce();
        
        // 构建签名
        $signStr = $timestamp . $nonce . $this->app_key . $this->client_secret;
        $sign = hash('sha256', $signStr);
        
        // 查询域名授权信息
        $response = $this->request('query_domain.php', [
            'app_key' => $this->app_key,
            'domain' => $domain,
            'timestamp' => $timestamp,
            'nonce' => $nonce,
            'sign' => $sign
        ]);
        
        return $response;
    }
    
    /**
     * 申请试用授权
     */
    public function applyTrial() {
        $domain = $this->getDomain();
        
        // 先初始化获取公钥
        $init_result = $this->init();
        if ($init_result['code'] != 200) {
            return $init_result;
        }
        
        $timestamp = time();
        $nonce = $this->generateNonce();
        
        // 构建签名 - 只使用app_key
        $signStr = $timestamp . $nonce . $this->app_key . $this->client_secret;
        $sign = hash('sha256', $signStr);
        
        // 构建内层数据 - 只使用domain，不传递fingerprint
        $innerData = [
            'timestamp' => $timestamp,
            'nonce' => $nonce,
            'sign' => $sign,
            'domain' => $domain
        ];
        
        // RSA加密
        $encryptedData = $this->rsaEncrypt(json_encode($innerData));
        if (!$encryptedData) {
            return array('code' => 500, 'message' => '数据加密失败');
        }
        
        $response = $this->request('trial.php', [
            'app_key' => $this->app_key,
            'data' => $encryptedData
        ]);
        
        if ($response['code'] == 200 && isset($response['data']['token'])) {
            // 保存token到数据库 - 使用domain作为标识
            $this->saveToken(
                $response['data']['token'],
                $response['data']['refresh_token'] ?? '',
                $response['data']['expire_time'],
                true  // 试用授权
            );
        }
        
        return $response;
    }
    
    /**
     * 激活授权
     */
    public function activate($auth_code) {
        $domain = $this->getDomain();
        
        // 先初始化获取公钥
        $init_result = $this->init();
        if ($init_result['code'] != 200) {
            return $init_result;
        }
        
        $timestamp = time();
        $nonce = $this->generateNonce();
        
        // 构建签名 - 只使用app_key和auth_code
        $signStr = $timestamp . $nonce . $this->app_key . $auth_code . $this->client_secret;
        $sign = hash('sha256', $signStr);
        
        // 构建内层数据 - 使用domain授权模式
        $innerData = [
            'timestamp' => $timestamp,
            'nonce' => $nonce,
            'sign' => $sign,
            'auth_code' => $auth_code,
            'domain' => $domain,
            'auth_type' => 'domain'  // 明确指定使用域名授权模式
        ];
        
        // RSA加密
        $encryptedData = $this->rsaEncrypt(json_encode($innerData));
        if (!$encryptedData) {
            return array('code' => 500, 'message' => '数据加密失败');
        }
        
        $response = $this->request('activate.php', [
            'app_key' => $this->app_key,
            'data' => $encryptedData
        ]);
        
        if ($response['code'] == 200 && isset($response['data']['token'])) {
            // 保存token到数据库 - 使用domain作为标识
            $this->saveToken(
                $response['data']['token'],
                $response['data']['refresh_token'] ?? '',
                $response['data']['expire_time'],
                false  // 正式授权
            );
        }
        
        return $response;
    }
    
    /**
     * 保存token到数据库
     */
    private function saveToken($token, $refresh_token, $expires_at, $is_trial = true) {
        $domain = $this->getDomain();
        $token_escaped = addslashes($token);
        $refresh_escaped = addslashes($refresh_token);
        $expire_escaped = addslashes($expires_at);
        $is_trial_int = $is_trial ? 1 : 0;
        // 使用domain作为device_id
        $device_escaped = addslashes($domain);
        
        $sql = "INSERT INTO `{$this->token_table}` (`token`, `refresh_token`, `domain`, `expires_at`, `is_trial`, `device_id`) 
                VALUES ('{$token_escaped}', '{$refresh_escaped}', '{$domain}', '{$expire_escaped}', {$is_trial_int}, '{$device_escaped}')
                ON DUPLICATE KEY UPDATE 
                `token` = '{$token_escaped}', 
                `refresh_token` = '{$refresh_escaped}',
                `expires_at` = '{$expire_escaped}',
                `is_trial` = {$is_trial_int},
                `device_id` = '{$device_escaped}'";
        
        $this->db->query($sql);
    }
    
    /**
     * 发送心跳
     */
    public function heartbeat($token = null) {
        if (empty($token)) {
            $stored = $this->db->get_row("SELECT * FROM `{$this->token_table}` WHERE `domain` = '{$this->getDomain()}'");
            if (!$stored) {
                return array('code' => 401, 'message' => '未找到授权信息');
            }
            $token = $stored['token'];
        }
        
        $timestamp = time();
        $nonce = $this->generateNonce();
        
        // 签名：timestamp + nonce + token值 + client_secret
        $signStr = $timestamp . $nonce . $token . $this->client_secret;
        $sign = hash('sha256', $signStr);
        
        $response = $this->request('heartbeat.php', [
            'timestamp' => $timestamp,
            'nonce' => $nonce,
            'token' => $token,
            'sign' => $sign
        ]);
        
        return $response;
    }
    
    /**
     * 查询授权信息
     */
    public function getAuthInfo($token = null) {
        if (empty($token)) {
            $stored = $this->db->get_row("SELECT * FROM `{$this->token_table}` WHERE `domain` = '{$this->getDomain()}'");
            if (!$stored) {
                return array('code' => 401, 'message' => '未找到授权信息');
            }
            $token = $stored['token'];
        }
        
        $response = $this->request('auth_info.php', [
            'token' => $token,
            'app_key' => $this->app_key
        ]);
        
        return $response;
    }
    
    /**
     * 刷新授权
     */
    public function refreshAuth() {
        $domain = $this->getDomain();
        
        // 先检查本地是否有token
        $stored = $this->db->get_row("SELECT * FROM `{$this->token_table}` WHERE `domain` = '{$domain}'");
        
        if ($stored && !empty($stored['token'])) {
            // 有token，去服务器验证token是否有效
            $auth_info = $this->getAuthInfo($stored['token']);
            
            if ($auth_info['code'] == 200 && isset($auth_info['data']['auth']['status']) && $auth_info['data']['auth']['status'] === 'active') {
                // token有效，更新本地信息（注意：auth_info.php返回的数据在auth子数组中）
                $auth_data = $auth_info['data']['auth'] ?? [];
                $expires_at = $auth_data['expire_time'] ?? $stored['expires_at'];
                $is_trial = $auth_data['is_trial'] ?? $stored['is_trial'];
                
                $this->saveToken(
                    $stored['token'],
                    $stored['refresh_token'],
                    $expires_at,
                    $is_trial
                );
                
                return array(
                    'code' => 200,
                    'message' => '授权刷新成功',
                    'data' => array(
                        'token' => $stored['token'],
                        'expires_at' => $expires_at,
                        'is_trial' => $is_trial,
                        'domain' => $domain
                    )
                );
            } else {
                // token无效或过期，尝试刷新token
                $refresh_result = $this->doRefreshToken($stored['token'], $stored['refresh_token']);
                if ($refresh_result['code'] == 200) {
                    return $refresh_result;
                }
            }
        }
        
        // 没有token或刷新失败，尝试申请试用
        return $this->applyTrial();
    }
    
    /**
     * 使用refresh_token刷新token
     */
    private function doRefreshToken($token, $refresh_token) {
        if (empty($refresh_token)) {
            return array('code' => 401, 'message' => '没有refresh_token');
        }
        
        $timestamp = time();
        $nonce = $this->generateNonce();
        
        // 构建签名
        $signStr = $timestamp . $nonce . $token . $this->client_secret;
        $sign = hash('sha256', $signStr);
        
        $response = $this->request('refresh.php', [
            'timestamp' => $timestamp,
            'nonce' => $nonce,
            'token' => $token,
            'refresh_token' => $refresh_token,
            'sign' => $sign
        ]);
        
        if ($response['code'] == 200 && isset($response['data']['token'])) {
            // 保存新token
            $this->saveToken(
                $response['data']['token'],
                $response['data']['refresh_token'] ?? '',
                $response['data']['expire_time'],
                $response['data']['is_trial'] ?? true
            );
        }
        
        return $response;
    }
    
    /**
     * 清除本地授权记录
     */
    public function clearAuth() {
        $domain = $this->getDomain();
        $this->db->query("DELETE FROM `{$this->token_table}` WHERE `domain` = '{$domain}'");
    }
    
    /**
     * 检查授权是否有效
     */
    public function isAuthValid() {
        $result = $this->getToken();
        return $result['code'] == 200;
    }
    
    /**
     * 获取剩余天数
     */
    public function getRemainDays() {
        $domain = $this->getDomain();
        $stored = $this->db->get_row("SELECT * FROM `{$this->token_table}` WHERE `domain` = '{$domain}'");
        if (!$stored) {
            return 0;
        }
        
        $expires_at = strtotime($stored['expires_at']);
        $remain_seconds = $expires_at - time();
        
        return max(0, floor($remain_seconds / 86400));
    }
}
