<?php
declare(strict_types=1);

namespace app\api\logic;

use app\dice\model\player\DicePlayer;
use app\api\cache\UserCache;
use plugin\saiadmin\exception\ApiException;
use Tinywan\Jwt\JwtToken;

/**
 * API 用户登录/注册逻辑（基于 DicePlayer 表）
 * 手机号格式限制：+60（马来西亚）
 */
class UserLogic
{
    /** 手机号正则：+60 开头，后跟 9–10 位数字（马来西亚） */
    private const PHONE_REGEX = '/^\+60\d{9,10}$/';

    /** 与 DicePlayerLogic 保持一致的密码盐，用于登录校验与注册写入 */
    private const PASSWORD_SALT = 'dice_player_salt_2024';

    /** 状态：正常 */
    private const STATUS_NORMAL = 1;

    /**
     * 手机号格式校验：+60 开头
     */
    public static function validatePhone(string $phone): void
    {
        if (!preg_match(self::PHONE_REGEX, $phone)) {
            throw new ApiException('手机号格式错误，仅支持 +60 开头的马来西亚号码（如 +60123456789）');
        }
    }

    /**
     * 与 DicePlayerLogic 一致的密码加密：md5(salt . password)
     */
    private function hashPassword(string $password): string
    {
        return md5(self::PASSWORD_SALT . $password);
    }

    /**
     * 登录（JSON：username, password, lang, coin, time）
     * 存在则校验密码并更新 coin（累加）；不存在则创建用户并写入 coin。
     * 将会话写入 Redis，返回 token 与前端连接地址。
     *
     * @param int|null $adminId 创建新用户时关联的后台管理员ID（sa_system_user.id），可选
     */
    public function loginByUsername(string $username, string $password, string $lang, float $coin, string $time, ?int $adminId = null): array
    {
        $username = trim($username);
        if ($username === '') {
            throw new ApiException('username 不能为空');
        }

        $player = DicePlayer::where('username', $username)->find();
        if ($player) {
            if ((int) ($player->status ?? 1) === 0) {
                throw new ApiException('账号已被禁用，无法登录');
            }
            $hashed = $this->hashPassword($password);
            if ($player->password !== $hashed) {
                throw new ApiException('密码错误');
            }
            $currentCoin = (float) $player->coin;
            $player->coin = $currentCoin + $coin;
            $player->save();
        } else {
            $player = new DicePlayer();
            $player->username = $username;
            $player->phone = $username;
            $player->password = $this->hashPassword($password);
            $player->status = self::STATUS_NORMAL;
            $player->coin = $coin;
            if ($adminId !== null && $adminId > 0) {
                $player->admin_id = $adminId;
            }
            $player->save();
        }

        $exp = (int) config('api.session_expire', 604800);
        $tokenResult = JwtToken::generateToken([
            'id' => (int) $player->id,
            'username' => $username,
            'plat' => 'api_login',
            'access_exp' => $exp,
        ]);
        $token = $tokenResult['access_token'];
        UserCache::setSessionByUsername($username, $token);

        $userArr = $player->hidden(['password', 'lottery_config_id', 't1_weight', 't2_weight', 't3_weight', 't4_weight', 't5_weight'])->toArray();
        UserCache::setUser((int) $player->id, $userArr);
        UserCache::setPlayerByUsername($username, $userArr);

        $baseUrl = rtrim(config('api.login_url_base', 'https://127.0.0.1:6777'), '/');
        $lang = in_array($lang, ['chs', 'en'], true) ? $lang : 'chs';
        $tokenInUrl = str_replace('%3D', '=', urlencode($token));
        $url = $baseUrl . '?token=' . $tokenInUrl . '&lang=' . $lang;

        return [
            'url' => $url,
            'token' => $token,
            'lang' => $lang,
            'user_id' => (int) $player->id,
            'user' => $userArr,
        ];
    }

    /**
     * 从 JWT 中解析 username（仅解码 payload，不校验签名与过期，用于退出时清除会话）
     */
    public static function getUsernameFromJwtPayload(string $token): ?string
    {
        $parts = explode('.', $token);
        if (count($parts) !== 3) {
            return null;
        }
        $payload = base64_decode(strtr($parts[1], '-_', '+/'), true);
        if ($payload === false) {
            return null;
        }
        $data = json_decode($payload, true);
        if (!is_array($data)) {
            return null;
        }
        $extend = $data['extend'] ?? $data;
        $username = $extend['username'] ?? null;
        return $username !== null ? trim((string) $username) : null;
    }

    /**
     * 从 Redis 获取用户信息（key = base64(user_id)），未命中则查 DicePlayer 并回写缓存
     */
    public static function getCachedUser(int $userId): array
    {
        $cached = UserCache::getUser($userId);
        if (!empty($cached)) {
            return $cached;
        }
        $user = DicePlayer::find($userId);
        if (!$user) {
            return [];
        }
        $arr = $user->hidden(['password'])->toArray();
        UserCache::setUser($userId, $arr);
        return $arr;
    }
}
