<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\ForgotPasswordRequest;
use App\Http\Requests\LoginRequest;
use App\Http\Requests\ResetPasswordRequest;
use App\Http\Requests\ResendTwoFactorCodeRequest;
use App\Http\Requests\VerifyTwoFactorRequest;
use App\Models\AuditLog;
use App\Models\User;
use App\Services\AuditService;
use App\Services\AuthService;
use App\Services\TwoFactorAuthService;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function __construct(
        private AuthService $authService,
        private AuditService $auditService,
    ) {
    }

    /**
     * Handle a login request.
     */
    public function login(LoginRequest $request): JsonResponse
    {
        $email = $request->validated()['email'];
        $ip    = $request->ip();

        try {
            $result = $this->authService->login($email, $request->validated()['password']);

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

            $this->auditService->success(
                AuditLog::ACTION_LOGIN_SUCCESS,
                AuditLog::ACTOR_ADMIN,
                $user?->id,
                $email,
                null, null,
                ['requires_2fa' => $result['requires_2fa'] ?? false],
                $ip,
            );

            if (isset($result['requires_2fa']) && $result['requires_2fa']) {
                return response()->json([
                    'success' => true,
                    'message' => 'Login successful',
                    'data' => $result,
                ]);
            }

            return response()->json([
                'success' => true,
                'message' => 'Login successful',
                'data' => [
                    'user' => [
                        'id' => $result['user']->id,
                        'name' => $result['user']->name,
                        'email' => $result['user']->email,
                        'email_verified_at' => $result['user']->email_verified_at?->toIso8601String(),
                        'roles' => $result['user']->getRoleNames(),
                    ],
                    'token' => $result['token'],
                ],
            ]);
        } catch (ValidationException $e) {
            $this->auditService->failed(
                AuditLog::ACTION_LOGIN_FAILED,
                AuditLog::ACTOR_ADMIN,
                null,
                $email,
                null, null, [], $ip,
            );

            return response()->json([
                'success' => false,
                'message' => 'Authentication failed',
                'errors' => $e->errors(),
            ], 401);
        }
    }

    /**
     * Handle a forgot password request.
     */
    public function forgotPassword(ForgotPasswordRequest $request): JsonResponse
    {
        $email = $request->validated()['email'];
        $ip    = $request->ip();

        try {
            $message = $this->authService->sendPasswordResetLink($email, $request->header('Origin'));

            $user = User::where('email', $email)->first();
            $this->auditService->success(
                AuditLog::ACTION_PASSWORD_RESET_REQUESTED,
                AuditLog::ACTOR_ADMIN,
                $user?->id,
                $email,
                null, null, [], $ip,
            );

            return response()->json([
                'success' => true,
                'message' => $message,
            ]);
        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Unable to send password reset link',
                'errors' => $e->errors(),
            ], 422);
        }
    }

    /**
     * Handle a reset password request.
     */
    public function resetPassword(ResetPasswordRequest $request): JsonResponse
    {
        $email = $request->validated()['email'];
        $ip    = $request->ip();

        try {
            $message = $this->authService->resetPassword(
                $email,
                $request->validated()['password'],
                $request->validated()['token'],
            );

            $user = User::where('email', $email)->first();
            $this->auditService->success(
                AuditLog::ACTION_PASSWORD_RESET_COMPLETED,
                AuditLog::ACTOR_ADMIN,
                $user?->id,
                $email,
                null, null, [], $ip,
            );

            return response()->json([
                'success' => true,
                'message' => $message,
            ]);
        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Unable to reset password',
                'errors' => $e->errors(),
            ], 422);
        }
    }

    /**
     * Verify 2FA code and complete login.
     */
    public function verifyTwoFactor(VerifyTwoFactorRequest $request): JsonResponse
    {
        $email = $request->validated('email');
        $ip    = $request->ip();

        try {
            $result = $this->authService->verifyTwoFactor(
                $email,
                $request->validated('code'),
                $request->validated('session_token'),
            );

            $this->auditService->success(
                AuditLog::ACTION_2FA_VERIFIED,
                AuditLog::ACTOR_ADMIN,
                $result['user']->id,
                $email,
                null, null, [], $ip,
            );

            return response()->json([
                'success' => true,
                'message' => 'Two-factor authentication successful',
                'data' => [
                    'user' => [
                        'id' => $result['user']->id,
                        'name' => $result['user']->name,
                        'email' => $result['user']->email,
                        'email_verified_at' => $result['user']->email_verified_at?->toIso8601String(),
                        'two_factor_enabled' => $result['user']->two_factor_enabled,
                        'roles' => $result['user']->getRoleNames(),
                    ],
                    'token' => $result['token'],
                ],
            ]);
        } catch (ValidationException $e) {
            $user = User::where('email', $email)->first();
            $this->auditService->failed(
                AuditLog::ACTION_2FA_FAILED,
                AuditLog::ACTOR_ADMIN,
                $user?->id,
                $email,
                null, null, [], $ip,
            );

            return response()->json([
                'success' => false,
                'message' => 'Verification failed',
                'errors' => $e->errors(),
            ], 422);
        }
    }

    /**
     * Resend 2FA code.
     */
    public function resendTwoFactorCode(ResendTwoFactorCodeRequest $request): JsonResponse
    {
        $email = $request->validated('email');
        $ip    = $request->ip();

        try {
            $user = User::where('email', $email)->first();

            if (! $user) {
                throw ValidationException::withMessages([
                    'email' => ['User not found.'],
                ]);
            }

            app(TwoFactorAuthService::class)->resendCode($user, $request->validated('session_token'));

            $this->auditService->success(
                AuditLog::ACTION_2FA_CODE_SENT,
                AuditLog::ACTOR_ADMIN,
                $user->id,
                $email,
                null, null, ['resend' => true], $ip,
            );

            return response()->json([
                'success' => true,
                'message' => 'Verification code resent successfully',
            ]);
        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to resend code',
                'errors' => $e->errors(),
            ], 422);
        }
    }
}

