<?php

declare(strict_types=1);

namespace app\api\controller\v1;

use ba\Random;
use Throwable;
use app\common\controller\Api;
use app\common\facade\Token;
use app\common\library\Auth as UserAuth;
use app\common\library\AgentJwt;
use app\common\model\MallPlayxUserAsset;
use app\admin\model\Admin;
use Webman\Http\Request;
use support\Response;

/**
 * API v1 鉴权接口
 */
class Auth extends Api
{
    /**
     * Agent Token 类型
     */
    public const TOKEN_TYPE = 'agent';

    /**
     * 时间戳有效范围（秒），防止重放攻击
     */
    protected int $timeTolerance = 300;

    /**
     * 临时登录 token 有效期（秒）
     */
    protected int $tempTokenExpire = 86400;

    /**
     * 获取鉴权 Token（GET 请求）
     * 参数仅从 Query 读取：signature、secret、agent_id、time
     * 返回：authtoken；失败返回 code=0 及失败信息
     */
    public function authToken(Request $request): Response
    {
        $response = $this->initializeApi($request);
        if ($response !== null) {
            return $response;
        }

        $signature = $request->get('signature', '');
        $secret = $request->get('secret', '');
        $agentId = $request->get('agent_id', '');
        $time = $request->get('time', '');

        if ($signature === '' || $secret === '' || $agentId === '' || $time === '') {
            return $this->error(__('Parameter signature/secret/agent_id/time can not be empty'));
        }

        $timestamp = intval($time);
        if ($timestamp <= 0) {
            return $this->error(__('Invalid timestamp'));
        }

        $now = time();
        if ($timestamp < $now - $this->timeTolerance || $timestamp > $now + $this->timeTolerance) {
            return $this->error(__('Timestamp expired'));
        }

        $admin = Admin::where('agent_id', $agentId)->find();
        if (!$admin) {
            return $this->error(__('Agent not found'));
        }

        $apiSecret = strval($admin->agent_api_secret ?? '');
        if ($apiSecret === '') {
            return $this->error(__('Agent not found'));
        }

        if ($apiSecret !== $secret) {
            return $this->error(__('Invalid agent or secret'));
        }

        $expectedSignature = strtoupper(md5($agentId . $secret . $time));
        if (!hash_equals($expectedSignature, $signature)) {
            return $this->error(__('Invalid signature'));
        }

        $expire = intval(config('buildadmin.agent_auth.token_expire', 86400));
        $payload = [
            'agent_id' => $agentId,
            'admin_id' => $admin->id,
        ];
        $authtoken = AgentJwt::encode($payload, $expire);

        return $this->success('', [
            'authtoken' => $authtoken,
        ]);
    }

    /**
     * H5 临时登录（GET/POST）
     * 参数：username
     * 写入或复用 mall_playx_user_asset；签发 muser 类型 token（user_id 为资产表主键）
     */
    public function temLogin(Request $request): Response
    {
        $response = $this->initializeApi($request);
        if ($response !== null) {
            return $response;
        }

        $enabled = config('buildadmin.agent_auth.temp_login_enable', false);
        if (!$enabled) {
            return $this->error(__('Temp login is disabled'));
        }

        $username = trim(strval($request->get('username', $request->post('username', ''))));
        if ($username === '') {
            return $this->error(__('Parameter username can not be empty'));
        }

        try {
            $asset = MallPlayxUserAsset::ensureForUsername($username);
        } catch (Throwable $e) {
            return $this->error($e->getMessage());
        }

        $token = Random::uuid();
        $refreshToken = Random::uuid();
        $expire = config('buildadmin.agent_auth.temp_login_expire', $this->tempTokenExpire);
        $assetId = intval($asset->getKey());
        Token::set($token, UserAuth::TOKEN_TYPE_MALL_USER, $assetId, $expire);
        Token::set($refreshToken, UserAuth::TOKEN_TYPE_MALL_USER . '-refresh', $assetId, 2592000);

        return $this->success('', [
            'userInfo' => [
                'id' => $assetId,
                'username' => strval($asset->username ?? ''),
                'nickname' => strval($asset->username ?? ''),
                'playx_user_id' => strval($asset->playx_user_id ?? ''),
                'token' => $token,
                'refresh_token' => $refreshToken,
                'expires_in' => $expire,
            ],
        ]);
    }
}
