<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Responses\ApiResponse;
use App\Models\User;
use App\Models\UserGroup;
use App\Services\HookManager;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Validation\ValidationException;

class UserAuthController extends Controller
{
    public function register(Request $request)
    {
        $validated = $request->validate([
            'username' => 'required|string|max:50|alpha_dash',
            'email' => 'nullable|string|max:100|email',
            'phone' => 'nullable|string|max:20',
            'password' => 'required|string|min:6|max:20|confirmed',
        ]);

        if (empty($validated['email']) && empty($validated['phone'])) {
            throw ValidationException::withMessages([
                'email' => ['邮箱和手机号至少填写一个'],
            ]);
        }

        $usernameExists = User::where('username', $validated['username'])->exists();
        if ($usernameExists) {
            throw ValidationException::withMessages([
                'username' => ['用户名已存在'],
            ]);
        }

        if (! empty($validated['email'])) {
            $emailExists = User::where('email', $validated['email'])->exists();
            if ($emailExists) {
                throw ValidationException::withMessages([
                    'email' => ['邮箱已被注册'],
                ]);
            }
        }

        if (! empty($validated['phone'])) {
            $phoneExists = User::where('phone', $validated['phone'])->exists();
            if ($phoneExists) {
                throw ValidationException::withMessages([
                    'phone' => ['手机号已被注册'],
                ]);
            }
        }

        $hookManager = app(HookManager::class);
        $validated = $hookManager->applyFilter('user.before_register', $validated);

        $defaultGroup = UserGroup::default()->enabled()->first();
        $groupId = $defaultGroup?->id;

        $user = User::create([
            'username' => $validated['username'],
            'email' => $validated['email'] ?? null,
            'phone' => $validated['phone'] ?? null,
            'password' => Hash::make($validated['password']),
            'group_id' => $groupId,
            'status' => 1,
        ]);

        $hookManager->doAction('user.after_register', $user);

        Auth::guard('web')->login($user);

        return response()->json(ApiResponse::success($user, '注册成功'));
    }

    public function login(Request $request)
    {
        $validated = $request->validate([
            'username' => 'nullable|string|max:100',
            'email' => 'nullable|string|email|max:100',
            'phone' => 'nullable|string|max:20',
            'password' => 'required|string|min:6|max:20',
        ]);

        if (empty($validated['username']) && empty($validated['email']) && empty($validated['phone'])) {
            throw ValidationException::withMessages([
                'username' => ['用户名、邮箱、手机号至少填写一个'],
            ]);
        }

        $throttleKey = strtolower($request->ip());

        if (RateLimiter::tooManyAttempts($throttleKey, 5)) {
            $seconds = RateLimiter::availableIn($throttleKey);
            throw ValidationException::withMessages([
                'password' => ["登录尝试过多，请 {$seconds} 秒后再试"],
            ]);
        }

        $credentials = $this->buildCredentials($validated);

        $hookManager = app(HookManager::class);
        $credentials = $hookManager->applyFilter('user.before_login', $credentials);

        if (! Auth::guard('web')->attempt($credentials)) {
            RateLimiter::hit($throttleKey, 60);

            throw ValidationException::withMessages([
                'password' => ['账号或密码错误'],
            ]);
        }

        RateLimiter::clear($throttleKey);

        $user = Auth::guard('web')->user();

        if (! $user->status->value) {
            Auth::guard('web')->logout();
            throw ValidationException::withMessages([
                'password' => ['账号已被禁用'],
            ]);
        }

        $user->incrementLoginCount($request->ip());

        $hookManager->doAction('user.after_login', $user);

        $request->session()->regenerate();

        return response()->json(ApiResponse::success($user, '登录成功'));
    }

    public function logout(Request $request)
    {
        $user = Auth::guard('web')->user();

        if ($user) {
            $hookManager = app(HookManager::class);
            $hookManager->doAction('user.before_logout', $user);
        }

        Auth::guard('web')->logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return response()->json(ApiResponse::success(null, '登出成功'));
    }

    public function info(Request $request)
    {
        $user = Auth::guard('web')->user();

        if (! $user) {
            return response()->json(ApiResponse::error(40003, '未登录'), 401);
        }

        return response()->json(ApiResponse::success($user->load('group')));
    }

    public function updateProfile(Request $request)
    {
        $user = Auth::guard('web')->user();

        if (! $user) {
            return response()->json(ApiResponse::error(40003, '未登录'), 401);
        }

        $validated = $request->validate([
            'nickname' => 'nullable|string|max:50',
            'avatar' => 'nullable|string|max:255',
            'gender' => 'nullable|integer|in:0,1,2',
            'birthday' => 'nullable|date',
            'signature' => 'nullable|string|max:255',
        ]);

        $hookManager = app(HookManager::class);
        $validated = $hookManager->applyFilter('user.profile.updating', $validated, $user);

        $user->update($validated);

        $hookManager->doAction('user.profile.updated', $user);

        return response()->json(ApiResponse::success($user->fresh()->load('group'), '更新成功'));
    }

    public function changePassword(Request $request)
    {
        $user = Auth::guard('web')->user();

        if (! $user) {
            return response()->json(ApiResponse::error(40003, '未登录'), 401);
        }

        $validated = $request->validate([
            'old_password' => 'required|string',
            'password' => 'required|string|min:6|max:20|confirmed',
        ]);

        if (! Hash::check($validated['old_password'], $user->password)) {
            throw ValidationException::withMessages([
                'old_password' => ['原密码错误'],
            ]);
        }

        $user->update([
            'password' => Hash::make($validated['password']),
        ]);

        return response()->json(ApiResponse::success(null, '密码修改成功'));
    }

    private function buildCredentials(array $validated): array
    {
        if (! empty($validated['username'])) {
            return [
                'username' => $validated['username'],
                'password' => $validated['password'],
            ];
        }

        if (! empty($validated['email'])) {
            return [
                'email' => $validated['email'],
                'password' => $validated['password'],
            ];
        }

        return [
            'phone' => $validated['phone'],
            'password' => $validated['password'],
        ];
    }

    public function sendResetEmailCode(Request $request)
    {
        $validated = $request->validate([
            'email' => 'required|email|max:100',
        ]);

        $user = User::where('email', $validated['email'])->first();

        if (! $user) {
            throw ValidationException::withMessages([
                'email' => ['该邮箱未注册'],
            ]);
        }

        $throttleKey = 'password_reset_email:'.strtolower($validated['email']);

        if (RateLimiter::tooManyAttempts($throttleKey, 3)) {
            $seconds = RateLimiter::availableIn($throttleKey);
            throw ValidationException::withMessages([
                'email' => ["发送过于频繁，请 {$seconds} 秒后再试"],
            ]);
        }

        RateLimiter::hit($throttleKey, 60);

        $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);

        Cache::put(
            'user_password_reset:'.$validated['email'].':'.$code,
            ['user_id' => $user->id, 'email' => $validated['email']],
            now()->addMinutes(10)
        );

        try {
            Mail::raw($validated['email'], function ($message) use ($code, $user) {
                $message->subject('【用户中心】密码重置验证码')
                    ->view('emails.password-reset-code', [
                        'code' => $code,
                        'nickname' => $user->nickname ?? $user->username,
                        'minutes' => 10,
                    ]);
            });
        } catch (\Throwable $e) {
            throw ValidationException::withMessages([
                'email' => ['邮件发送失败，请检查邮件配置或稍后重试'],
            ]);
        }

        return response()->json(ApiResponse::success(null, '验证码已发送'));
    }

    public function resetPasswordByCode(Request $request)
    {
        $validated = $request->validate([
            'email' => 'required|email|max:100',
            'code' => 'required|string|size:6',
            'password' => 'required|string|min:6|max:20',
            'password_confirmation' => 'required|string|min:6|max:20',
        ]);

        if ($validated['password'] !== $validated['password_confirmation']) {
            throw ValidationException::withMessages([
                'password' => ['两次密码输入不一致'],
            ]);
        }

        $cacheKey = 'user_password_reset:'.$validated['email'].':'.$validated['code'];
        $cached = Cache::get($cacheKey);

        if (! $cached) {
            throw ValidationException::withMessages([
                'code' => ['验证码无效或已过期'],
            ]);
        }

        Cache::forget($cacheKey);

        $user = User::find($cached['user_id']);

        if (! $user || $user->status->value === 0) {
            throw ValidationException::withMessages([
                'email' => ['账号不存在或已被禁用'],
            ]);
        }

        $user->update(['password' => Hash::make($validated['password'])]);

        return response()->json(ApiResponse::success(null, '密码重置成功'));
    }
}
