<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\User;
use hg\apidoc\annotation as Apidoc;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rules\Password;
use Spatie\Permission\Models\Role;

#[Apidoc\Title('认证模块')]
class AuthController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:api')->except(['login', 'applyAccount']);
        $this->middleware(function (Request $request, \Closure $next) {
            /** @var User|null $user */
            $user = Auth::guard('api')->user();
            if (! $user || ! $user->force_password_change) {
                return $next($request);
            }

            $allowed = [
                'auth/me',
                'auth/password',
                'auth/logout',
                'api/auth/me',
                'api/auth/password',
                'api/auth/logout',
            ];

            if (in_array($request->path(), $allowed, true)) {
                return $next($request);
            }

            return response()->json([
                'code' => 423,
                'message' => '请先修改密码后再继续操作',
                'data' => ['force_password_change' => true],
            ], 423);
        })->except(['login', 'applyAccount']);
    }

    #[Apidoc\Title('登录'), Apidoc\Method('POST'), Apidoc\Url('/auth/login')]
    public function login(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'email' => ['nullable', 'email', 'required_without:phone'],
            'phone' => ['nullable', 'string', 'max:32', 'required_without:email'],
            'password' => ['required', 'string'],
        ]);
        $credentials = ['password' => (string) $validated['password']];
        $accountType = '';

        if (! empty($validated['email'])) {
            $credentials['email'] = (string) $validated['email'];
            $accountType = 'email';
        }

        if (! empty($validated['phone'])) {
            $credentials['phone'] = (string) $validated['phone'];
            $accountType = 'phone';
        }

        $token = Auth::guard('api')->attempt($credentials);

        if (! $token) {
            return response()->json(['code' => 401, 'message' => '账号或密码错误', 'data' => null], 401);
        }

        /** @var User|null $user */
        $user = Auth::guard('api')->user();
        $permissionCount = (int) ($user?->getAllPermissions()->count() ?? 0);
        if ($permissionCount <= 0) {
            Auth::guard('api')->logout();

            return response()->json([
                'code' => 403,
                'message' => '账号申请已通过，但尚未开通任何权限，请联系管理员分配权限后再登录',
                'data' => null,
            ], 403);
        }

        $this->auditLog($request, 'login', ['metadata' => ['account_type' => $accountType]]);

        return response()->json([
            'code' => 0,
            'message' => 'ok',
            'data' => [
                'token' => $token,
                'type' => 'bearer',
                'expires_in' => Auth::guard('api')->factory()->getTTL() * 60,
            ],
        ]);
    }

    #[Apidoc\Title('账号申请'), Apidoc\Method('POST'), Apidoc\Url('/auth/apply-account')]
    public function applyAccount(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'nickname' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email', 'max:255', 'unique:users,email'],
            'phone' => ['required', 'string', 'max:32', 'unique:users,phone'],
            'password' => ['required', 'confirmed', Password::min(6)],
        ]);

        $user = User::query()->create([
            'nickname' => $validated['nickname'],
            'email' => $validated['email'],
            'phone' => $validated['phone'],
            'password' => $validated['password'],
            'force_password_change' => false,
        ]);

        $guestRole = Role::query()->firstOrCreate(
            ['name' => 'guest', 'guard_name' => 'api'],
            ['name' => 'guest', 'guard_name' => 'api']
        );
        $user->syncRoles([$guestRole->id]);

        $this->auditLog($request, 'account_apply', ['metadata' => ['target_user_id' => $user->id]]);

        return response()->json([
            'code' => 0,
            'message' => '申请提交成功，请联系或等待管理员开通权限后登录控制台',
            'data' => null,
        ], 201);
    }

    #[Apidoc\Title('当前用户信息'), Apidoc\Method('GET'), Apidoc\Url('/auth/me')]
    public function me(): JsonResponse
    {
        /** @var User $user */
        $user = Auth::guard('api')->user();

        return response()->json([
            'code' => 0,
            'message' => 'ok',
            'data' => [
                'user' => $user?->load('roles'),
                'permissions' => $user?->getAllPermissions()->pluck('name')->values(),
                'force_password_change' => (bool) ($user?->force_password_change ?? false),
            ],
        ]);
    }

    #[Apidoc\Title('更新个人信息'), Apidoc\Method('PUT'), Apidoc\Url('/auth/profile')]
    public function updateProfile(Request $request): JsonResponse
    {
        /** @var User $user */
        $user = Auth::guard('api')->user();

        $validated = $request->validate([
            'nickname' => ['sometimes', 'required', 'string', 'max:255'],
            'email' => ['sometimes', 'required', 'email', 'max:255', 'unique:users,email,'.$user->id],
            'phone' => ['nullable', 'string', 'max:32', 'unique:users,phone,'.$user->id],
        ]);

        $user->update($validated);
        $this->auditLog($request, 'profile_update');

        return response()->json(['code' => 0, 'message' => 'ok', 'data' => $user->fresh(['roles'])]);
    }

    #[Apidoc\Title('修改密码'), Apidoc\Method('PUT'), Apidoc\Url('/auth/password')]
    public function updatePassword(Request $request): JsonResponse
    {
        /** @var User $user */
        $user = Auth::guard('api')->user();

        $rules = [
            'password' => ['required', 'confirmed', Password::min(6)],
        ];

        if (! $user->force_password_change) {
            $rules['current_password'] = ['required', 'current_password:api'];
        }

        $validated = $request->validate($rules);

        $user->password = $validated['password'];
        $user->force_password_change = false;
        $user->save();
        $this->auditLog($request, 'password_update');

        return response()->json(['code' => 0, 'message' => 'ok', 'data' => null]);
    }

    #[Apidoc\Title('登出'), Apidoc\Method('POST'), Apidoc\Url('/auth/logout')]
    public function logout(Request $request): JsonResponse
    {
        $this->auditLog($request, 'logout');
        Auth::guard('api')->logout();

        return response()->json(['code' => 0, 'message' => 'ok', 'data' => null]);
    }
}
