<?php

namespace app\api\controller;

use ba\Date;
use ba\Captcha;
use ba\Random;
use app\common\library\finance\WithdrawFlow;
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 app\common\facade\Token as TokenFacade;
use support\think\Db;
use support\validation\Validator;
use support\validation\ValidationException;
use Webman\Http\Request;
use support\Response;

class Account extends Frontend
{
    protected array $noNeedLogin = ['retrievePassword'];
    // 移动端 API 不走会员权限表（user_group/user_rule）校验，仅校验登录态
    protected array $noNeedPermission = ['*'];

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

        $authToken = trim((string) $request->header('auth-token', ''));
        if ($authToken === '') {
            return $this->mobileResult(1101, 'Missing auth-token');
        }
        $tokenData = TokenFacade::get($authToken);
        $type = $tokenData['type'] ?? '';
        $expireTime = $tokenData['expire_time'] ?? 0;
        if ($type !== 'auth-token' || !is_numeric($expireTime) || $expireTime < time()) {
            return $this->mobileResult(1101, 'auth-token is invalid or expired');
        }

        $user = $this->auth->getUser();
        $userId = intval(strval($user->id));
        $coinBalance = WithdrawFlow::amountString($user->coin ?? '0');

        // 打码量 / 提现配额快照
        $flow = WithdrawFlow::status($userId, [
            'total_deposit_coin'  => $user->total_deposit_coin ?? '0',
            'total_withdraw_coin' => $user->total_withdraw_coin ?? '0',
            'bet_flow_coin'       => $user->bet_flow_coin ?? '0',
        ]);
        $maxWithdrawable = WithdrawFlow::maxWithdrawable($coinBalance, $flow);

        // 待审核提现订单数（配合 /api/finance/withdrawCreate 的 3 笔上限）
        $pendingWithdrawCount = Db::name('withdraw_order')
            ->where('user_id', $userId)
            ->where('status', 0)
            ->count();

        $payload = [
            'code' => 1,
            'message' => __('ok'),
            'data' => [
                'uuid'                 => $user->uuid ?? '',
                'username'             => $user->username,
                'head_image'           => $user->avatar ?? '',
                'phone'                => $user->phone ?? '',
                'email'                => $user->email ?? '',
                'register_invite_code' => $user->register_invite_code ?? '',
                'channel_id'           => $user->channel_id,
                'risk_flags'           => $user->risk_flags ?? 0,
                'current_streak'       => $user->current_streak ?? 0,
                'last_bet_period_no'   => $user->last_bet_period_no ?? '',
                'create_time'          => $user->create_time ?? 0,

                // 资金字段（4 位小数字符串，与钱包展示口径一致）
                'coin'                 => floatval($coinBalance),
                'coin_balance'         => floatval($coinBalance),
                'frozen_balance'       => 0.00,
                'total_deposit_coin'   => floatval(WithdrawFlow::amountString($user->total_deposit_coin ?? '0')),
                'total_withdraw_coin'  => floatval(WithdrawFlow::amountString($user->total_withdraw_coin ?? '0')),
                'bet_flow_coin'        => floatval($flow['bet_flow_coin']),
                'max_withdrawable'     => floatval($maxWithdrawable),
                'withdraw_flow'        => [
                    'ratio'                => floatval($flow['ratio']),
                    'net_deposit'          => floatval($flow['net_deposit']),
                    'required_bet_flow'    => floatval($flow['required_bet_flow']),
                    'remaining_bet_flow'   => floatval($flow['remaining_bet_flow']),
                    'eligible'             => $flow['eligible'],
                    'max_withdraw_by_flow' => $flow['flow_unlimited'] ? null : floatval($flow['max_withdraw_by_flow']),
                    'flow_unlimited'       => $flow['flow_unlimited'],
                    'pending_withdraw'     => [
                        'count' => $pendingWithdrawCount,
                        'max'   => WithdrawFlow::MAX_PENDING_WITHDRAW,
                    ],
                ],
            ],
        ];
        return \response(json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 200, ['Content-Type' => 'application/json']);
    }

    private function mobileResult(int $code, string $message, array $data = []): Response
    {
        $payload = [
            'code' => $code,
            'message' => __($message),
            'data' => $data,
        ];
        return \response(json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 200, ['Content-Type' => 'application/json']);
    }

    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}$/',
                    '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());
            }

            $existUser = User::where('username', $data['username'])->where('id', '<>', $this->auth->id)->find();
            if ($existUser) {
                return $this->error(__('Username') . ' ' . __('already exists'));
            }

            $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']}")) {
            try {
                if ($params['type'] == 'email') {
                    Validator::make($params, ['email' => 'required|email'])->validate();
                    if (User::where('email', $params['email'])->find()) {
                        return $this->error(__('Email') . ' ' . __('already exists'));
                    }
                } else {
                    Validator::make($params, ['mobile' => 'required|regex:/^1[3-9]\d{9}$/'])->validate();
                    if (User::where('mobile', $params['mobile'])->find()) {
                        return $this->error(__('Mobile') . ' ' . __('already exists'));
                    }
                }
            } 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~'));
    }
}
