<?php

declare(strict_types=1);

namespace app\api\controller;

use app\common\facade\Token;
use app\common\library\Auth as UserAuth;
use app\common\model\User;
use ba\Random;
use support\think\Db;
use Webman\Http\Request;
use support\Response;

class Auth extends MobileBase
{
    protected array $noNeedLogin = ['register', 'login', 'refreshToken', 'userRegister', 'userLogin', 'tokenRefresh'];
    protected array $noNeedAuthToken = ['register', 'refreshToken', 'userRegister', 'tokenRefresh'];

    public function userRegister(Request $request): Response
    {
        $response = $this->initializeMobile($request);
        if ($response !== null) {
            return $response;
        }

        $username = trim((string) $request->post('username', ''));
        if ($username === '') {
            $username = trim((string) $request->post('account', ''));
        }
        $password = (string) $request->post('password', '');
        $inviteCode = trim((string) $request->post('invite_code', ''));

        if ($username === '' || $password === '') {
            return $this->mobileError(1001, 'Missing parameters');
        }
        if ($inviteCode === '') {
            return $this->mobileError(1001, 'Invite code required');
        }
        if (!preg_match('/^1[3-9]\d{9}$/', $username)) {
            return $this->mobileError(1003, 'Please enter the correct mobile number');
        }

        $phone = $username;
        $email = '';

        if (User::where('username', $username)->find() || User::where('phone', $username)->find()) {
            return $this->mobileError(2003, 'Account already registered', [
                'already_registered' => true,
            ]);
        }

        $extend = [];
        $inviterAdmin = Db::name('admin')->field(['id', 'channel_id'])->where('invite_code', $inviteCode)->find();
        if (!$inviterAdmin) {
            return $this->mobileError(2002, 'Invite code does not exist');
        }
        $extend['register_invite_code'] = $inviteCode;
        $extend['admin_id'] = $inviterAdmin['id'];
        $channelId = $inviterAdmin['channel_id'] ?? null;
        if ($channelId === null || $channelId === '' || (int) $channelId <= 0) {
            return $this->mobileError(2002, 'Invite code not bound to channel');
        }
        $extend['channel_id'] = (int) $channelId;
        $channelStatus = Db::name('channel')->where('id', (int) $channelId)->value('status');
        if (intval($channelStatus) !== 1) {
            return $this->mobileError(2002, 'Channel disabled');
        }

        $registered = $this->auth->register($username, $password, $phone, $email, 1, $extend);
        if (!$registered) {
            $dup = $this->auth->getRegisterDuplicateKind();
            if ($dup === 'username' || $dup === 'email' || $dup === 'phone') {
                return $this->mobileError(2003, 'Account already registered', [
                    'already_registered' => true,
                ]);
            }
            return $this->mobileError(2000, (string) $this->auth->getError());
        }

        $loggedIn = $this->auth->login($username, $password, true);
        if (!$loggedIn) {
            return $this->mobileError(2000, 'Registered successfully but login failed');
        }

        return $this->mobileSuccess($this->buildLoginPayload());
    }

    public function userLogin(Request $request): Response
    {
        $response = $this->initializeMobile($request);
        if ($response !== null) {
            return $response;
        }

        $username = trim((string) $request->post('username', ''));
        if ($username === '') {
            $username = trim((string) $request->post('account', ''));
        }
        $password = (string) $request->post('password', '');
        if ($username === '' || $password === '') {
            return $this->mobileError(1001, 'Missing parameters');
        }

        $ok = $this->auth->login($username, $password, true);
        if (!$ok) {
            return $this->mobileError(1101, 'Incorrect account or password');
        }
        return $this->mobileSuccess($this->buildLoginPayload());
    }

    public function tokenRefresh(Request $request): Response
    {
        $response = $this->initializeMobile($request);
        if ($response !== null) {
            return $response;
        }

        $refreshToken = trim((string) $request->post('refresh_token', ''));
        if ($refreshToken === '') {
            return $this->mobileError(1001, 'Missing parameters');
        }

        $tokenData = Token::get($refreshToken);
        if (!$tokenData || $tokenData['type'] !== UserAuth::TOKEN_TYPE . '-refresh' || $tokenData['expire_time'] < time()) {
            return $this->mobileError(1101, 'Login status has expired');
        }

        $newToken = Random::uuid();
        Token::set($newToken, UserAuth::TOKEN_TYPE, $tokenData['user_id'], config('buildadmin.user_token_keep_time', 259200));
        return $this->mobileSuccess([
            'user-token' => $newToken,
            'expires_in' => config('buildadmin.user_token_keep_time', 259200),
        ]);
    }

    private function buildLoginPayload(): array
    {
        $userInfo = $this->auth->getUserInfo();
        return [
            'user-token' => $userInfo['token'] ?? '',
            'refresh_token' => $userInfo['refresh_token'] ?? '',
            'expires_in' => config('buildadmin.user_token_keep_time', 259200),
            'user' => [
                'username' => $userInfo['username'] ?? '',
                'uuid' => $userInfo['uuid'] ?? '',
                'coin' => $userInfo['coin'] ?? '0.00',
                'channel_id' => $userInfo['channel_id'] ?? null,
                'risk_flags' => $userInfo['risk_flags'] ?? 0,
            ],
        ];
    }
}

