<?php

namespace App\Http\Controllers\Portal;

use App\Http\Controllers\Controller;
use App\Http\Requests\PortalLoginRequest;
use App\Http\Requests\ResendTwoFactorCodeRequest;
use App\Http\Requests\SetPasswordRequest;
use App\Http\Requests\VerifyTwoFactorRequest;
use App\Models\AuditLog;
use App\Models\PortalUser;
use App\Notifications\TwoFactorDisabledNotification;
use App\Notifications\TwoFactorEnabledNotification;
use App\Services\AuditService;
use App\Services\PortalAuthService;
use App\Services\PortalUserService;
use App\Services\TwoFactorAuthService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function __construct(
        private readonly PortalUserService $portalUserService,
        private readonly PortalAuthService $portalAuthService,
        private readonly AuditService $auditService,
    ) {}

    /**
     * Set password from invitation token.
     */
    public function setPassword(SetPasswordRequest $request): JsonResponse
    {
        $portalUser = $this->portalUserService->setPasswordFromInvitation(
            $request->validated('token'),
            $request->validated('email'),
            $request->validated('password'),
        );

        $this->auditService->success(
            AuditLog::ACTION_SET_PASSWORD,
            AuditLog::ACTOR_PORTAL_USER,
            $portalUser->id,
            $portalUser->email,
            'PortalUser', $portalUser->id,
            ['role' => $portalUser->role],
            $request->ip(),
        );

        return response()->json([
            'success' => true,
            'message' => 'Password set successfully. You can now log in.',
            'data' => [
                'user' => [
                    'id' => $portalUser->id,
                    'name' => $portalUser->name,
                    'email' => $portalUser->email,
                    'role' => $portalUser->role,
                ],
            ],
        ]);
    }

    /**
     * Log in a portal user.
     */
    public function login(PortalLoginRequest $request): JsonResponse
    {
        $email = $request->validated('email');
        $ip    = $request->ip();

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

            $portalUser = PortalUser::where('email', $email)->first();
            $this->auditService->success(
                AuditLog::ACTION_LOGIN_SUCCESS,
                AuditLog::ACTOR_PORTAL_USER,
                $portalUser?->id,
                $email,
                null, null,
                ['role' => $portalUser?->role, 'requires_2fa' => $result['requires_2fa'] ?? false],
                $ip,
            );

            return response()->json([
                'success' => true,
                'message' => 'Login successful',
                'data' => $result,
            ]);
        } catch (ValidationException $e) {
            $this->auditService->failed(
                AuditLog::ACTION_LOGIN_FAILED,
                AuditLog::ACTOR_PORTAL_USER,
                null,
                $email,
                null, null, [], $ip,
            );

            throw $e;
        }
    }

    /**
     * Log out the authenticated portal user.
     */
    public function logout(Request $request): JsonResponse
    {
        $user = $request->user();

        $this->auditService->success(
            AuditLog::ACTION_LOGOUT,
            AuditLog::ACTOR_PORTAL_USER,
            $user->id,
            $user->email,
            'PortalUser', $user->id,
            ['role' => $user->role],
            $request->ip(),
        );

        $this->portalAuthService->logout($user);

        return response()->json([
            'success' => true,
            'message' => 'Logged out successfully',
        ]);
    }

    /**
     * Get the authenticated portal user's details.
     */
    public function me(Request $request): JsonResponse
    {
        $user = $request->user();
        $user->load('companyEmployee');

        $userData = [
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
            'role' => $user->role,
            'company_id' => $user->company_id,
            'email_verified_at' => $user->email_verified_at?->toIso8601String(),
            'created_at' => $user->created_at->toIso8601String(),
        ];

        // Add employee-specific data if user is an employee
        if ($user->role === 'employee' && $user->companyEmployee) {
            $employee = $user->companyEmployee;
            $userData['employee_id'] = $employee->id; // Use this ID in URLs like /api/portal/employees/{id}/...
            $userData['nin_verification'] = [
                'has_submitted_nin' => $employee->hasSubmittedNin(),
                'is_nin_verified' => $employee->isNinVerified(),
                'is_validated' => $employee->is_validated ?? false,
                'nin_verified_at' => $employee->nin_verified_at?->toIso8601String(),
            ];
        }

        return response()->json([
            'success' => true,
            'data' => $userData,
        ]);
    }

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

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

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

            return response()->json([
                'success' => true,
                'message' => 'Two-factor authentication successful',
                'data' => $result,
            ]);
        } catch (ValidationException $e) {
            $portalUser = PortalUser::where('email', $email)->first();
            $this->auditService->failed(
                AuditLog::ACTION_2FA_FAILED,
                AuditLog::ACTOR_PORTAL_USER,
                $portalUser?->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 {
            $portalUser = PortalUser::where('email', $email)->first();

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

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

            $this->auditService->success(
                AuditLog::ACTION_2FA_CODE_SENT,
                AuditLog::ACTOR_PORTAL_USER,
                $portalUser->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);
        }
    }

    /**
     * Enable 2FA for the authenticated portal user.
     */
    public function enableTwoFactor(Request $request): JsonResponse
    {
        $user = $request->user();

        if ($user->hasTwoFactorEnabled()) {
            return response()->json([
                'success' => false,
                'message' => 'Two-factor authentication is already enabled',
            ], 422);
        }

        $user->enableTwoFactor();
        $user->notify(new TwoFactorEnabledNotification);

        $this->auditService->success(
            AuditLog::ACTION_2FA_ENABLED,
            AuditLog::ACTOR_PORTAL_USER,
            $user->id,
            $user->email,
            'PortalUser', $user->id,
            [], $request->ip(),
        );

        return response()->json([
            'success' => true,
            'message' => 'Two-factor authentication has been enabled',
            'data' => [
                'two_factor_enabled' => true,
            ],
        ]);
    }

    /**
     * Disable 2FA for the authenticated portal user.
     */
    public function disableTwoFactor(Request $request): JsonResponse
    {
        $user = $request->user();

        if (! $user->canDisableTwoFactor()) {
            return response()->json([
                'success' => false,
                'message' => 'You cannot disable two-factor authentication',
            ], 403);
        }

        if (! $user->hasTwoFactorEnabled()) {
            return response()->json([
                'success' => false,
                'message' => 'Two-factor authentication is not enabled',
            ], 422);
        }

        $user->disableTwoFactor();
        $user->notify(new TwoFactorDisabledNotification);

        $this->auditService->success(
            AuditLog::ACTION_2FA_DISABLED,
            AuditLog::ACTOR_PORTAL_USER,
            $user->id,
            $user->email,
            'PortalUser', $user->id,
            [], $request->ip(),
        );

        return response()->json([
            'success' => true,
            'message' => 'Two-factor authentication has been disabled',
            'data' => [
                'two_factor_enabled' => false,
            ],
        ]);
    }
}

