<?php

namespace App\Services;

use App\Http\Responses\ApiResponse;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class AppMarketService
{
    protected function getApiUrl(): string
    {
        return rtrim(config('apps.market.api_url'), '/');
    }

    protected function getApiKey(): string
    {
        return config('apps.market.api_key', '');
    }

    protected function getCmsproVersion(): string
    {
        // 优先使用数据库中的系统版本记录（升级后自动更新）
        $version = system_version();
        if ($version) {
            return $version;
        }
        // 兜底使用 APP_VERSION 环境变量
        return (string) config('app.version', '');
    }

    protected function getCacheTtl(): int
    {
        return config('apps.market.cache_ttl', 3600);
    }

    protected function getHeaders(): array
    {
        $headers = [
            'Accept' => 'application/json',
        ];

        if ($this->getApiKey()) {
            $headers['Authorization'] = 'Bearer ' . $this->getApiKey();
        }

        return $headers;
    }

    protected function httpClient()
    {
        return Http::withHeaders($this->getHeaders())
            ->withOptions([
                // 关闭 SSL 证书验证（本地调试用，生产环境请删除这两行）
                'verify' => false,
            ]);
    }

    /**
     * 去除域名 www. 前缀，用于兼容 www 子域名比较
     */
    protected function normalizeDomain(string $domain): string
    {
        return preg_replace('/^www\./i', '', $domain);
    }

    public function getApps(array $params = []): array
    {
        if (!config('apps.market.enabled')) {
            return ApiResponse::error(50012, '应用市场未启用');
        }

        try {
            $cacheKey = 'market_apps_' . md5(json_encode($params));

            $data = Cache::remember($cacheKey, $this->getCacheTtl(), function () use ($params) {
                $response = $this->httpClient()->get($this->getApiUrl() . '/api/market/apps', $params);

                if (!$response->successful()) {
                    return null;
                }

                $json = $response->json();
                return $json['data'] ?? null;
            });

            if ($data === null) {
                return ApiResponse::error(50012, '应用市场服务不可用1');
            }

            return ApiResponse::success($data);
        } catch (\Throwable $e) {
            Log::error('应用市场请求失败', ['error' => $e->getMessage()]);

            return ApiResponse::error(50012, '应用市场服务不可用2');
        }
    }

    public function getAppDetail(string $appId): array
    {
        if (!config('apps.market.enabled')) {
            return ApiResponse::error(50012, '应用市场未启用');
        }

        try {
            $cacheKey = "market_app_detail_{$appId}";

            $data = Cache::remember($cacheKey, $this->getCacheTtl(), function () use ($appId) {
                $response = $this->httpClient()->get($this->getApiUrl() . "/api/market/apps/{$appId}");

                if (!$response->successful()) {
                    return null;
                }

                $json = $response->json();
                return $json['data'] ?? null;
            });

            if ($data === null) {
                return ApiResponse::error(50006, '应用不存在');
            }

            return ApiResponse::success($data);
        } catch (\Throwable $e) {
            Log::error('应用市场请求失败', ['error' => $e->getMessage()]);

            return ApiResponse::error(50012, '应用市场服务不可用3');
        }
    }

    public function downloadPackage(string $appId, string $version): string
    {
        $packagePath = config('apps.package_path');
        if (!\Illuminate\Support\Facades\File::isDirectory($packagePath)) {
            \Illuminate\Support\Facades\File::makeDirectory($packagePath, 0755, true);
        }

        $zipPath = "{$packagePath}/{$appId}-{$version}.zip";

        try {
            $apiUrl = $this->getApiUrl() . "/api/market/apps/{$appId}/download";
            Log::info('应用市场：请求下载应用包', [
                'app_id' => $appId,
                'version' => $version,
                'url' => $apiUrl,
            ]);

            $postData = [];
            if ($version && $version !== 'latest') {
                $postData['version'] = $version;
            }

            $response = $this->httpClient()->post($apiUrl, $postData);

            if (!$response->successful()) {
                $status = $response->status();
                $body = $response->body();
                Log::error('应用市场：下载接口返回错误', [
                    'app_id' => $appId,
                    'status' => $status,
                    'body' => mb_substr($body, 0, 500),
                ]);

                $json = $response->json();
                $errMsg = $json['message'] ?? $json['msg'] ?? null;
                throw new \RuntimeException($errMsg ?: "市场接口返回HTTP {$status}");
            }

            $contentType = $response->header('Content-Type');

            if ($contentType && str_contains($contentType, 'application/zip')) {
                \Illuminate\Support\Facades\File::put($zipPath, $response->body());
                return $zipPath;
            }

            $json = $response->json();

            if (isset($json['code']) && $json['code'] !== 0) {
                $errMsg = $json['message'] ?? '未知错误';
                Log::error('应用市场：下载接口返回业务错误', [
                    'app_id' => $appId,
                    'code' => $json['code'],
                    'message' => $errMsg,
                ]);
                throw new \RuntimeException($errMsg);
            }

            $downloadUrl = $json['data']['download_url'] ?? $json['download_url'] ?? null;

            if ($downloadUrl) {
                $fileResponse = $this->httpClient()->get($downloadUrl);
                if (!$fileResponse->successful()) {
                    throw new \RuntimeException('下载链接请求失败：HTTP ' . $fileResponse->status());
                }
                \Illuminate\Support\Facades\File::put($zipPath, $fileResponse->body());
                return $zipPath;
            }

            Log::error('应用市场：响应中无下载链接', [
                'app_id' => $appId,
                'content_type' => $contentType,
                'response_keys' => array_keys($json ?? []),
                'data_keys' => array_keys($json['data'] ?? []),
            ]);
            throw new \RuntimeException('市场接口未返回应用包下载地址');
        } catch (\Throwable $e) {
            Log::error('应用包下载失败', ['app_id' => $appId, 'error' => $e->getMessage()]);

            throw new \RuntimeException('应用下载失败：' . $e->getMessage());
        }
    }

    public function checkAppUpdate(string $appId, string $currentVersion): ?array
    {
        if (!config('apps.market.enabled')) {
            return null;
        }

        try {
            $cacheKey = "market_app_update_{$appId}_{$currentVersion}";

            return Cache::remember($cacheKey, $this->getCacheTtl(), function () use ($appId, $currentVersion) {
                $response = $this->httpClient()->get($this->getApiUrl() . "/api/market/apps/{$appId}/versions");

                if (!$response->successful()) {
                    return null;
                }

                $json = $response->json();
                $data = $json['data'] ?? [];

                if (empty($data)) {
                    return null;
                }

                // 过滤出比当前版本高的所有版本
                $availableVersions = collect($data)
                    ->filter(fn ($v) => version_compare($v['version'], $currentVersion, '>'))
                    ->values()
                    ->all();

                if (empty($availableVersions)) {
                    return null;
                }

                // 按 semver 升序排列（version_compare 返回 -1/0/1，需用 usort）
                usort($availableVersions, fn ($a, $b) => version_compare($a['version'], $b['version']));

                $latest = $availableVersions[count($availableVersions) - 1];
                $next = $availableVersions[0];

                return [
                    // 向后兼容字段（对应最新版本）
                    'version' => $latest['version'],
                    'changelog' => $latest['changelog'] ?? null,
                    // 新增字段：完整版本信息
                    'current_version' => $currentVersion,
                    'latest_version' => $latest['version'],
                    'next_version' => $next['version'],
                    'available_versions' => array_map(fn ($v) => [
                        'version' => $v['version'],
                        'changelog' => $v['changelog'] ?? null,
                    ], $availableVersions),
                ];
            });
        } catch (\Throwable) {
            return null;
        }
    }

    public function getCategories(): array
    {
        if (!config('apps.market.enabled')) {
            return ApiResponse::error(50012, '应用市场未启用');
        }

        try {
            $cacheKey = 'market_categories';

            $data = Cache::remember($cacheKey, $this->getCacheTtl(), function () {
                $response = $this->httpClient()->get($this->getApiUrl() . '/api/market/categories');

                if (!$response->successful()) {
                    return null;
                }

                $json = $response->json();
                return $json['data'] ?? null;
            });

            if ($data === null) {
                return ApiResponse::error(50012, '应用市场服务不可用4');
            }

            return ApiResponse::success($data);
        } catch (\Throwable $e) {
            return ApiResponse::error(50012, '应用市场服务不可用5');
        }
    }

    /**
     * 获取当前站点 site_key
     */
    protected function getSiteKey(): string
    {
        return (string) config('apps.site_key', '');
    }

    /**
     * 获取当前站点域名
     */
    protected function getSiteDomain(): string
    {
        return request()->getHost();
    }

    /**
     * 获取站点注册状态（含域名一致性校验）
     *
     * 检查本地 CMSPRO_SITE_KEY 是否存在，并远程校验与服务端的域名是否一致。
     */
    public function getSiteStatus(): array
    {
        $siteKey = $this->getSiteKey();
        $domain = $this->getSiteDomain();
        $marketEnabled = (bool) config('apps.market.enabled');

        $data = [
            'registered' => !empty($siteKey),
            'domain' => $domain,
            'site_key' => $siteKey ? substr($siteKey, 0, 8) . '***' : '',
        ];

        // 有 site_key 时，远程校验域名一致性
        if (!empty($siteKey) && $marketEnabled) {
            try {
                $response = $this->httpClient()
                    ->get($this->getApiUrl() . '/api/market/site/check', [
                        'site_key' => $siteKey,
                        'domain' => $domain,
                        'cmspro_version' => $this->getCmsproVersion(),
                    ]);

                $result = $response->json();

                if (isset($result['code']) && $result['code'] === 0 && isset($result['data'])) {
                    $data['remote_domain'] = $result['data']['domain'] ?? '';
                    $data['domain_match'] = $this->normalizeDomain($result['data']['domain'] ?? '') === $this->normalizeDomain($domain);
                    $data['remote_registered'] = $result['data']['registered'] ?? false;
                }
            } catch (\Throwable $e) {
                Log::warning('站点状态远程校验失败', ['error' => $e->getMessage()]);
            }
        }

        return ApiResponse::success($data);
    }

    /**
     * 远程注册站点（调用 v5.cmspro.cn 的 /api/market/site/register）
     *
     * 传递本地域名和 CMSPRO_SITE_KEY 到服务端。
     * 服务端逻辑：
     *   - site_key 不存在 → 直接注册（无需验证）
     *   - site_key 存在且域名一致 → 更新活跃时间
     *   - site_key 存在但域名不一致 → HTTP 反向验证，失败返回 verify_failed
     *
     * @param bool $force 人工确认模式，跳过 HTTP 反向验证（内网环境使用）
     */
    public function registerSite(bool $force = false): array
    {
        if (!config('apps.market.enabled')) {
            return ApiResponse::error(50012, '应用市场未启用');
        }

        $domain = $this->getSiteDomain();
        $siteKey = $this->getSiteKey();

        if (empty($siteKey)) {
            // 本地无 site_key，先生成一个
            $siteKey = bin2hex(random_bytes(16));
            $this->writeEnvKey('CMSPRO_SITE_KEY', $siteKey);
        }

        try {
            $params = [
                'domain' => $domain,
                'site_key' => $siteKey,
                'cmspro_version' => $this->getCmsproVersion(),
            ];
            if ($force) {
                $params['force'] = true;
            }

            $response = $this->httpClient()
                ->post($this->getApiUrl() . '/api/market/site/register', $params);

            $result = $response->json();

            if (isset($result['code']) && $result['code'] === 0 && isset($result['data'])) {
                // 检查是否需要人工确认（verify_failed）
                if (!empty($result['data']['verify_failed'])) {
                    return ApiResponse::success([
                        'verify_failed' => true,
                        'old_domain' => $result['data']['old_domain'] ?? '',
                        'new_domain' => $result['data']['new_domain'] ?? $domain,
                        'site_key' => $siteKey,
                    ], $result['message'] ?? '域名验证失败，可能是内网环境');
                }

                // 注册成功
                $remoteSiteKey = $result['data']['site_key'] ?? $siteKey;

                // 如果服务端返回的 site_key 与本地不同，更新 .env
                if ($remoteSiteKey !== $siteKey) {
                    $this->writeEnvKey('CMSPRO_SITE_KEY', $remoteSiteKey);
                }

                return ApiResponse::success([
                    'site_key' => $remoteSiteKey,
                    'auto_written' => true,
                    'is_new' => $result['data']['is_new'] ?? false,
                    'verified' => $result['data']['verified'] ?? true,
                ], '站点注册成功，site_key 已同步，请重启服务使配置生效');
            }

            return ApiResponse::error(50009, $result['message'] ?? '注册失败');
        } catch (\Throwable $e) {
            Log::error('站点注册失败', ['error' => $e->getMessage()]);
            return ApiResponse::error(50012, '连接市场服务端失败');
        }
    }

    /**
     * 将本地 site_key 同步到服务端（域名变更后使用）
     *
     * 当本地域名与服务端记录不一致时，用户可选择将本地信息同步到服务端。
     */
    public function syncSiteIdentity(): array
    {
        if (!config('apps.market.enabled')) {
            return ApiResponse::error(50012, '应用市场未启用');
        }

        $domain = $this->getSiteDomain();
        $siteKey = $this->getSiteKey();

        if (empty($siteKey)) {
            return ApiResponse::error(50012, '本地无 CMSPRO_SITE_KEY，请先注册站点');
        }

        try {
            $response = $this->httpClient()
                ->post($this->getApiUrl() . '/api/market/site/register', [
                    'domain' => $domain,
                    'site_key' => $siteKey,
                    'cmspro_version' => $this->getCmsproVersion(),
                ]);

            $result = $response->json();

            if (isset($result['code']) && $result['code'] === 0) {
                return ApiResponse::success([], '站点身份已同步到服务端');
            }

            return ApiResponse::error(50009, $result['message'] ?? '同步失败');
        } catch (\Throwable $e) {
            Log::error('站点身份同步失败', ['error' => $e->getMessage()]);
            return ApiResponse::error(50012, '连接市场服务端失败');
        }
    }

    /**
     * 写入/更新 .env 文件中的指定配置项
     *
     * @param string $key   配置键名（如 CMSPRO_SITE_KEY）
     * @param string $value 配置值
     * @return bool 是否写入成功
     */
    protected function writeEnvKey(string $key, string $value): bool
    {
        $envPath = base_path('.env');

        if (!file_exists($envPath) || !is_writable($envPath)) {
            Log::warning('.env 文件不可写', ['path' => $envPath]);
            return false;
        }

        $content = file_get_contents($envPath);
        $pattern = '/^' . preg_quote($key, '/') . '=.*/m';
        $replacement = $key . '=' . $value;

        if (preg_match($pattern, $content)) {
            // 已存在，替换
            $content = preg_replace($pattern, $replacement, $content);
        } else {
            // 不存在，追加
            $content = rtrim($content) . "\n" . $replacement . "\n";
        }

        $result = file_put_contents($envPath, $content);

        if ($result !== false) {
            Log::info('已写入 .env 配置', ['key' => $key]);

            // 立即更新运行时 config 值，无需重启即可生效
            if ($key === 'CMSPRO_SITE_KEY') {
                config(['apps.site_key' => $value]);
            }

            // 清除配置缓存，使下次请求读取新值
            try {
                \Illuminate\Support\Facades\Artisan::call('config:clear');
            } catch (\Throwable $e) {
                // 缓存清除失败不影响主流程
            }
        }

        return $result !== false;
    }

    /**
     * 远程创建购买订单（调用 v5.cmspro.cn 的 /api/market/purchase/create）
     *
     * v5.cmspro.cn 的 MarketApiController::createPurchase 会：
     * 1. 校验 site_key、应用存在性和价格
     * 2. 调用 Onlinepay 创建支付订单（type=recharge）
     * 3. 返回支付二维码供前端展示
     */
    public function createPurchase(array $data): array
    {
        if (!config('apps.market.enabled')) {
            Log::warning('应用市场未启用');
            return ApiResponse::error(50012, '应用市场未启用');
        }

        $siteKey = $this->getSiteKey();
        if (empty($siteKey)) {
            Log::warning('站点未注册，site_key为空', ['siteKey' => $siteKey]);
            return ApiResponse::error(50009, '站点未注册，请先在系统设置中注册站点');
        }

        $requestData = array_merge($data, ['site_key' => $siteKey]);
        $apiUrl = $this->getApiUrl() . '/api/market/purchase/create';
        
        Log::info('创建购买订单请求开始', [
            'api_url' => $apiUrl,
            'request_data_keys' => array_keys($requestData),
            'request_data' => $requestData,
            'site_key_prefix' => $siteKey ? substr($siteKey, 0, 8) . '***' : 'N/A'
        ]);

        try {
            $response = $this->httpClient()
                ->timeout(30)
                ->post($apiUrl, $requestData);

            $responseStatus = $response->status();
            $responseBody = $response->body();
            $result = $response->json() ?: [];
            
            Log::info('创建购买订单响应', [
                'status_code' => $responseStatus,
                'response_body' => $responseBody,
                'result' => $result
            ]);

            if ($responseStatus === 200 || $responseStatus === 201) {
                if (isset($result['code']) && $result['code'] === 0) {
                    Log::info('创建购买订单成功', ['request_id' => $result['data']['id'] ?? 'N/A']);
                    return ApiResponse::success($result['data'] ?? []);
                }

                Log::warning('创建购买订单失败', [
                    'error_code' => $result['code'] ?? 'N/A',
                    'error_message' => $result['message'] ?? '未知错误'
                ]);
                return ApiResponse::error(
                    $result['code'] ?? 50008,
                    $result['message'] ?? '创建购买订单失败'
                );
            } else {
                Log::error('创建购买订单HTTP错误', [
                    'http_status' => $responseStatus,
                    'response_body' => $responseBody
                ]);
                return ApiResponse::error(50008, 'HTTP {$responseStatus}请求错误：' . $responseBody);
            }
        } catch (\Throwable $e) {
            Log::error('远程创建购买订单异常', [
                'error_message' => $e->getMessage(),
                'error_code' => $e->getCode(),
                'trace' => $e->getTraceAsString(),
                'request_url' => $apiUrl,
                'request_data' => $requestData
            ]);
            return ApiResponse::error(50012, '连接市场服务端失败：' . $e->getMessage());
        }
    }

    /**
     * 远程查询购买订单状态
     */
    public function queryPurchase(string $outTradeNo): array
    {
        if (!config('apps.market.enabled')) {
            return ApiResponse::error(50012, '应用市场未启用');
        }

        $siteKey = $this->getSiteKey();
        if (empty($siteKey)) {
            return ApiResponse::error(50009, '站点未注册');
        }

        try {
            $response = $this->httpClient()
                ->get($this->getApiUrl() . '/api/market/purchase/query', [
                    'site_key' => $siteKey,
                    'out_trade_no' => $outTradeNo,
                ]);

            $result = $response->json();

            if (isset($result['code']) && $result['code'] === 0) {
                return ApiResponse::success($result['data'] ?? []);
            }

            return ApiResponse::error(
                $result['code'] ?? 50008,
                $result['message'] ?? '查询失败'
            );
        } catch (\Throwable $e) {
            Log::error('远程查询购买订单失败', ['error' => $e->getMessage()]);
            return ApiResponse::error(50012, '连接市场服务端失败');
        }
    }

    /**
     * 远程获取已购买应用列表
     */
    public function getPurchasedApps(): array
    {
        if (!config('apps.market.enabled')) {
            return ApiResponse::error(50012, '应用市场未启用');
        }

        $siteKey = $this->getSiteKey();
        if (empty($siteKey)) {
            // 站点未注册时返回空列表，不阻断页面加载
            return ApiResponse::success([]);
        }

        try {
            $response = $this->httpClient()
                ->get($this->getApiUrl() . '/api/market/purchased', [
                    'site_key' => $siteKey,
                ]);

            $result = $response->json();

            if (isset($result['code']) && $result['code'] === 0) {
                $data = $result['data'] ?? [];
                // 归一化：兼容远程返回纯字符串数组 ['cmspro.opencode']
                // 和对象数组 [{'app_id': 'cmspro.opencode'}] 两种格式
                if (!empty($data) && is_string($data[0] ?? null)) {
                    $data = array_map(fn ($id) => ['app_id' => $id], $data);
                }
                // 过滤掉 app_id 为空的脏数据
                $data = array_values(array_filter($data, fn ($item) => !empty($item['app_id'])));
                return ApiResponse::success($data);
            }

            return ApiResponse::success([]);
        } catch (\Throwable $e) {
            Log::error('远程获取已购买应用列表失败', ['error' => $e->getMessage()]);
            return ApiResponse::success([]);
        }
    }
}