<?php

namespace app\api\controller;

use app\common\controller\Api;
use app\common\model\OtaVersion;
use think\Exception;
use think\Log;

/**
 * OTA 远程升级接口
 *
 * 无需鉴权，公开接口
 */
class Ota extends Api
{
    // 无需登录
    protected $noNeedLogin = ['checkVersion'];
    // 无需鉴权
    protected $noNeedRight = ['*'];

    /**
     * 检查设备版本更新
     *
     * GET /api/ota/checkVersion
     *
     * @param string $imei    设备 Android ID
     * @param string $version 当前版本名
     * @param string $build   当前构建号
     */
    public function checkVersion()
    {
        $imei    = $this->request->get('imei', '');
        $version = $this->request->get('version', '');
        $build   = $this->request->get('build', '');

        if (empty($imei)) {
            $this->error('设备标识不能为空');
        }

        // 记录检查日志
        Log::info("OTA检查: imei={$imei}, version={$version}, build={$build}");

        // 查询最新已发布版本
        $latestVersion = OtaVersion::where('status', 'published')
            ->order('version_code', 'desc')
            ->find();

        if (!$latestVersion) {
            $this->error('暂无可用版本');
        }

        // 转换为整数比较版本号
        $localBuild = intval($build);
        $serverBuild = intval($latestVersion['version_code']);

        // 如果云端版本不高于本地版本，返回无更新
        if ($serverBuild <= $localBuild) {
            $this->success('已是最新版本', null);
        }

        // 检查最低版本限制
        if (!empty($latestVersion['min_version'])) {
            // 简单字符串比较版本名
            if (version_compare($version, $latestVersion['min_version'], '<')) {
                $this->error('当前版本过低，请先升级到 ' . $latestVersion['min_version']);
            }
        }

        // 检查设备白名单（如果设置了 target_devices）
        if (!empty($latestVersion['target_devices'])) {
            $targets = array_map('trim', explode(',', $latestVersion['target_devices']));
            if (!in_array($imei, $targets)) {
                $this->error('该设备不在此次升级范围内');
            }
        }

        // 构建返回数据
        $apkUrl = $this->buildApkUrl($latestVersion['apk_file']);
        $sha256 = $latestVersion['sha256'] ?: '';

        // 如果 sha256 为空或 fileSize 为空，尝试从文件计算
        if (empty($sha256) || empty($latestVersion['file_size'])) {
            $fileInfo = $this->calculateFileInfo($latestVersion['apk_file']);
            if ($fileInfo) {
                if (empty($sha256)) {
                    $sha256 = $fileInfo['sha256'];
                    // 可选：自动更新数据库
                    // OtaVersion::update(['sha256' => $sha256], ['id' => $latestVersion['id']]);
                }
                if (empty($latestVersion['file_size'])) {
                    $latestVersion['file_size'] = $fileInfo['file_size'];
                }
            }
        }

        $data = [
            'versionName'   => $latestVersion['version_name'],
            'versionCode'   => (int)$latestVersion['version_code'],
            'downloadUrl'   => $apkUrl,
            'updateLog'     => $latestVersion['update_log'],
            'fileSize'      => (int)($latestVersion['file_size'] ?? 0),
            'sha256'        => $sha256,
            'isForceUpdate' => (bool)$latestVersion['is_force_update'],
        ];

        $this->success('发现新版本', $data);
    }

    /**
     * 构建 APK 下载 URL
     *
     * 客户端要求必须使用 HTTPS 协议，此处强制转换为 HTTPS。
     * 兼容数据库中可能出现的重复 /uploads/ 前缀。
     *
     * @param string $relativePath 相对路径（可能含 /uploads/ 前缀）
     * @return string 完整 HTTPS URL
     */
    private function buildApkUrl($relativePath)
    {
        $domain = request()->domain();
        // 强制使用 HTTPS
        $domain = preg_replace('/^http:\/\//i', 'https://', $domain);
        // 去除重复的 /uploads/ 前缀（如 /uploads/uploads/ → /uploads/）
        $relativePath = preg_replace('#^/?(uploads/)+#', 'uploads/', $relativePath);
        return rtrim($domain, '/') . '/' . $relativePath;
    }

    /**
     * 计算 APK 文件的 SHA-256 和文件大小
     *
     * @param string $relativePath 相对路径
     * @return array|null ['sha256' => string, 'file_size' => int]
     */
    private function calculateFileInfo($relativePath)
    {
        $fullPath = ROOT_PATH . 'public' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . ltrim($relativePath, '/');
        if (!file_exists($fullPath)) {
            return null;
        }

        $fileSize = filesize($fullPath);
        $sha256 = hash_file('sha256', $fullPath);

        return [
            'sha256'    => $sha256,
            'file_size' => $fileSize,
        ];
    }
}