<?php

/**
 * 文件功能：认证控制器 (处理登录即注册等逻辑)
 *
 * @author   ChatRoom Laravel
 *
 * @version  1.0.0
 */

namespace App\Http\Controllers;

use App\Http\Requests\LoginRequest;
use App\Models\Sysparam;
use App\Models\User;
use App\Models\UsernameBlacklist;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redis;

/**
 * 类功能：处理聊天室前台登录、自动注册与退出登录。
 */
class AuthController extends Controller
{
    /**
     * 处理用户登录/注册尝试。
     * 逻辑：
     * 1. 如果用户已存在，验证密码。为了兼容老数据库，先验证Bcrypt，再退化验证MD5。如果MD5正确则升级为Bcrypt。
     * 2. 如果用户不存在，直接注册新用户并登录。
     */
    public function login(LoginRequest $request): JsonResponse
    {
        $credentials = $request->validated();
        $username = $credentials['username'];
        $password = $credentials['password'];
        $ip = $request->ip();

        $user = User::where('username', $username)->first();

        if ($user) {
            // 用户存在，验证密码
            $passwordMatches = false;
            try {
                $passwordMatches = Hash::check($password, $user->password);
            } catch (\RuntimeException $e) {
                // Hash::check() in Laravel 11/12 throws if the hash isn't a valid bcrypt string
                $passwordMatches = false;
            }

            if ($passwordMatches) {
                // Bcrypt 验证通过

                // 检测是否被封禁 (后台管理员级别获得豁免权，防止误把自己关在门外)
                $adminLevel = (int) Sysparam::getValue('superlevel', '100');
                if ($user->user_level < $adminLevel) {
                    if ($user->user_level < 0) {
                        return response()->json(['status' => 'error', 'message' => '您的账号已被管理员封禁，无法登录。'], 403);
                    }
                    if (Redis::sismember('banned_ips', $ip)) {
                        return response()->json(['status' => 'error', 'message' => '您所在的 IP 地址已被管理员封禁，限制访问。'], 403);
                    }
                }

                $this->performLogin($user, $ip, $request);

                return response()->json(['status' => 'success', 'message' => '登录成功']);
            }

            // 退化为 MD5 验证（兼容原 ASP 系统的老密码）
            if (md5($password) === $user->password) {
                // MD5 验证通过，升级密码为 Bcrypt
                $user->password = Hash::make($password);
                $user->save();

                // 检测是否被封禁 (后台管理员级别获得豁免权，防止误把自己关在门外)
                $adminLevel = (int) Sysparam::getValue('superlevel', '100');
                if ($user->user_level < $adminLevel) {
                    if ($user->user_level < 0) {
                        return response()->json(['status' => 'error', 'message' => '您的账号已被管理员封禁，无法登录。'], 403);
                    }
                    if (Redis::sismember('banned_ips', $ip)) {
                        return response()->json(['status' => 'error', 'message' => '您所在的 IP 地址已被管理员封禁，限制访问。'], 403);
                    }
                }

                $this->performLogin($user, $ip, $request);

                return response()->json(['status' => 'success', 'message' => '登录成功，且安全策略已自动升级']);
            }

            // 密码错误
            return response()->json([
                'status' => 'error',
                'message' => '密码错误，请重试。',
            ], 422);
        }

        // --- 核心：第一次登录即为注册 ---

        // 映射性别：1=男 2=女 0=保密（数据库 sex 列为 int）
        $sex = (int) $request->input('bSex', 0);
        if (! in_array($sex, [1, 2])) {
            $sex = 0;
        }

        // 新注册用户：只检测 IP 封禁 (新号不存在账号封禁)
        if (Redis::sismember('banned_ips', $ip)) {
            return response()->json(['status' => 'error', 'message' => '您所在的 IP 地址已被管理员封禁，禁止注册新账号。'], 403);
        }

        // 检测用户名是否在禁用词列表（永久禁用 或 改名临时保留期内）
        if ($blockingRecord = UsernameBlacklist::getBlockingRecord($username)) {
            $reason = '';
            if ($blockingRecord->type === 'permanent') {
                $reason = "（包含违禁敏感词：{$blockingRecord->username}）";
            }

            return response()->json(['status' => 'error', 'message' => "该用户名已被系统禁止注册{$reason}，请更换其他名称。"], 422);
        }

        // --- 提取邀请人 Cookie ---
        $inviterIdCookie = $request->cookie('inviter_id');
        $inviterId = null;
        if ($inviterIdCookie && is_numeric($inviterIdCookie)) {
            // 简单校验邀请人是否存在，防止脏数据
            if (User::where('id', $inviterIdCookie)->exists()) {
                $inviterId = (int) $inviterIdCookie;
            }
        }

        $newUser = User::create([
            'username' => $username,
            'password' => Hash::make($password),
            'first_ip' => $ip,
            'last_ip' => $ip,
            'user_level' => 1, // 默认普通用户等级
            'sex' => $sex,
            'usersf' => '1.gif', // 默认头像
            'inviter_id' => $inviterId, // 记录邀请人
        ]);

        $this->performLogin($newUser, $ip, $request);

        // 如果是通过邀请注册的，响应成功后建议清除 Cookie，防止污染后续注册
        if ($inviterId) {
            \Illuminate\Support\Facades\Cookie::queue(\Illuminate\Support\Facades\Cookie::forget('inviter_id'));
        }

        return response()->json(['status' => 'success', 'message' => '注册并登录成功！']);
    }

    /**
     * 执行实际的登录操作并记录时间、IP 等。
     */
    private function performLogin(User $user, string $ip, Request $request): void
    {
        Auth::login($user);
        // 登录成功后立即轮换 session id，阻断会话固定攻击。
        $request->session()->regenerate();

        // 递增访问次数
        $user->increment('visit_num');

        // 更新最后登录IP和时间（同时将旧IP转移到 previous_ip 作上次登录记录）
        $user->update([
            'previous_ip' => $user->last_ip,
            'last_ip' => $ip,
            'log_time' => now(),
            'in_time' => now(),
        ]);

        // 可选：将用户登录状态也同步写入原有的 IpLog 模型，以便数据归档查询
        \App\Models\IpLog::create([
            'ip' => $ip,
            'sdate' => now(),
            'uuname' => $user->username,
        ]);

        // 触发微信机器人消息推送 (登录上线类)
        try {
            $wechatService = new \App\Services\WechatBot\WechatNotificationService;
            $wechatService->notifyAdminOnline($user);
            $wechatService->notifyFriendsOnline($user);
            $wechatService->notifySpouseOnline($user);
        } catch (\Exception $e) {
            \Illuminate\Support\Facades\Log::error('WechatBot presence notification failed', ['error' => $e->getMessage()]);
        }
    }

    /**
     * 退出登录，清除会话后跳转回登录首页
     */
    public function logout(Request $request): \Illuminate\Http\RedirectResponse
    {
        if (Auth::check()) {
            $user = Auth::user();
            // 记录退出时间和退出信息
            $user->update([
                'out_time' => now(),
                'out_info' => '正常退出了聊天室',
            ]);

            // [NEW] 同步清除该用户在所有房间的在线状态和心跳，确保其如果马上重登，能触发全新入场欢迎
            try {
                $chatState = app(\App\Services\ChatStateService::class);
                $roomIds = $chatState->getUserRooms($user->username);
                foreach ($roomIds as $roomId) {
                    $chatState->userLeave($roomId, $user->username);
                }
            } catch (\Exception $e) {
                // 忽略清理缓存时发生的异常
            }
        }

        Auth::logout();

        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect('/')->with('success', '您已成功退出聊天室，欢迎下次再来！');
    }
}
