<?php

namespace app\api\controller;

use ba\Date;
use ba\Captcha;
use ba\Random;
use app\common\model\User;
use app\common\facade\Token;
use app\common\model\UserScoreLog;
use app\common\model\UserMoneyLog;
use app\common\controller\Frontend;
use support\validation\Validator;
use support\validation\ValidationException;
use Webman\Http\Request;
use support\Response;

class Account extends Frontend
{
    protected array $noNeedLogin = ['retrievePassword'];
    protected array $noNeedPermission = ['verification', 'changeBind'];

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

        $sevenDays = Date::unixTime('day', -6);
        $score = $money = $days = [];
        for ($i = 0; $i < 7; $i++) {
            $days[$i] = date("Y-m-d", $sevenDays + ($i * 86400));
            $tempToday0 = strtotime($days[$i]);
            $tempToday24 = strtotime('+1 day', $tempToday0) - 1;
            $score[$i] = UserScoreLog::where('user_id', $this->auth->id)
                ->where('create_time', 'BETWEEN', $tempToday0 . ',' . $tempToday24)
                ->sum('score');
            $userMoneyTemp = UserMoneyLog::where('user_id', $this->auth->id)
                ->where('create_time', 'BETWEEN', $tempToday0 . ',' . $tempToday24)
                ->sum('money');
            $money[$i] = bcdiv((string) $userMoneyTemp, '100', 2);
        }

        return $this->success('', [
            'days' => $days,
            'score' => $score,
            'money' => $money,
        ]);
    }

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

        if ($request->method() === 'POST') {
            $model = $this->auth->getUser();
            $data = $request->only(['avatar', 'username', 'nickname', 'gender', 'birthday', 'motto']);
            $data['id'] = $this->auth->id;
            if (!isset($data['birthday'])) {
                $data['birthday'] = null;
            }

            try {
                Validator::make($data, [
                    'username' => 'required|string|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/|unique:user,username,' . $this->auth->id,
                    'nickname' => 'required|string|regex:/^[\x{4e00}-\x{9fa5}a-zA-Z0-9_-]+$/u',
                    'birthday' => 'nullable|date',
                ], [
                    'nickname.regex' => __('nicknameChsDash'),
                ])->validate();
            } catch (ValidationException $e) {
                return $this->error($e->getMessage());
            }

            $model->startTrans();
            try {
                $model->save($data);
                $model->commit();
            } catch (\Throwable $e) {
                $model->rollback();
                return $this->error($e->getMessage());
            }

            return $this->success(__('Data updated successfully~'));
        }

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

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

        $captcha = new Captcha();
        $params = $request->only(['type', 'captcha']);
        $key = ($params['type'] == 'email' ? $this->auth->email : $this->auth->mobile) . "user_{$params['type']}_verify";
        if ($captcha->check($params['captcha'], $key)) {
            $uuid = Random::uuid();
            Token::set($uuid, $params['type'] . '-pass', $this->auth->id, 600);
            return $this->success('', [
                'type' => $params['type'],
                'accountVerificationToken' => $uuid,
            ]);
        }
        return $this->error(__('Please enter the correct verification code'));
    }

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

        $captcha = new Captcha();
        $params = $request->only(['type', 'captcha', 'email', 'mobile', 'accountVerificationToken', 'password']);
        $user = $this->auth->getUser();

        if ($user[$params['type']]) {
            if (!Token::check($params['accountVerificationToken'], $params['type'] . '-pass', $user->id)) {
                return $this->error(__('You need to verify your account before modifying the binding information'));
            }
        } elseif (!isset($params['password']) || !verify_password($params['password'], $user->password, ['salt' => $user->salt])) {
            return $this->error(__('Password error'));
        }

        if ($captcha->check($params['captcha'], $params[$params['type']] . "user_change_{$params['type']}")) {
            $rules = $params['type'] == 'email'
                ? ['email' => 'required|email|unique:user,email']
                : ['mobile' => 'required|regex:/^1[3-9]\d{9}$/|unique:user,mobile'];
            try {
                Validator::make($params, $rules)->validate();
            } catch (ValidationException $e) {
                return $this->error(__($e->getMessage()));
            }
            if ($params['type'] == 'email') {
                $user->email = $params['email'];
            } else {
                $user->mobile = $params['mobile'];
            }
            Token::delete($params['accountVerificationToken']);
            $user->save();
            return $this->success();
        }
        return $this->error(__('Please enter the correct verification code'));
    }

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

        if ($request->method() === 'POST') {
            $model = $this->auth->getUser();
            $params = $request->only(['oldPassword', 'newPassword']);

            if (!verify_password($params['oldPassword'], $model->password, ['salt' => $model->salt])) {
                return $this->error(__('Old password error'));
            }

            try {
                Validator::make(
                    ['password' => $params['newPassword']],
                    ['password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/'],
                    ['password.regex' => __('Please input correct password')]
                )->validate();
            } catch (ValidationException $e) {
                return $this->error($e->getMessage());
            }

            $model->startTrans();
            try {
                $model->resetPassword($this->auth->id, $params['newPassword']);
                $model->commit();
            } catch (\Throwable $e) {
                $model->rollback();
                return $this->error($e->getMessage());
            }

            $this->auth->logout();
            return $this->success(__('Password has been changed, please login again~'));
        }
        return $this->error(__('Method not allowed'), [], 0, ['statusCode' => 405]);
    }

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

        $limit = $request->get('limit', $request->post('limit', 15));
        $res = UserScoreLog::where('user_id', $this->auth->id)
            ->order('create_time', 'desc')
            ->paginate($limit);

        return $this->success('', [
            'list' => $res->items(),
            'total' => $res->total(),
        ]);
    }

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

        $limit = $request->get('limit', $request->post('limit', 15));
        $res = UserMoneyLog::where('user_id', $this->auth->id)
            ->order('create_time', 'desc')
            ->paginate($limit);

        return $this->success('', [
            'list' => $res->items(),
            'total' => $res->total(),
        ]);
    }

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

        $params = $request->only(['type', 'account', 'captcha', 'password']);
        try {
            Validator::make($params, [
                'type' => 'required|in:email,mobile',
                'account' => 'required|string',
                'captcha' => 'required|string',
                'password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/',
            ], [
                'password.regex' => __('Please input correct password'),
            ])->validate();
        } catch (ValidationException $e) {
            return $this->error($e->getMessage());
        }

        if ($params['type'] == 'email') {
            $user = User::where('email', $params['account'])->find();
        } else {
            $user = User::where('mobile', $params['account'])->find();
        }
        if (!$user) {
            return $this->error(__('Account does not exist~'));
        }

        $captchaObj = new Captcha();
        if (!$captchaObj->check($params['captcha'], $params['account'] . 'user_retrieve_pwd')) {
            return $this->error(__('Please enter the correct verification code'));
        }

        if ($user->resetPassword($user->id, $params['password'])) {
            return $this->success(__('Password has been changed~'));
        }
        return $this->error(__('Failed to modify password, please try again later~'));
    }
}
