<?php

namespace App\Http\Controllers\Api;

use App\Models\Invitation;
use App\Models\User;
use App\Services\EmailVerificationService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;

class AuthController extends BaseApiController
{
    public function __construct(
        private EmailVerificationService $emailVerificationService,
    ) {}

    /**
     * Register a new user via invitation token.
     */
    public function register(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'firstname' => 'required|string|max:255',
                'surname' => 'required|string|max:255',
                'middlename' => 'nullable|string|max:255',
                'email' => 'required|email|unique:users',
                'phone' => 'required|string|unique:users',
                'password' => 'required|string|min:8',
                'password_confirmation' => 'required|string|same:password',
                'date_of_birth' => 'nullable|date',
                'gender' => 'nullable|in:male,female,other',
                'invitation_token' => 'required|string',
            ]);

            // Validate invitation token
            $invitation = Invitation::where('token', $validated['invitation_token'])
                ->whereNull('accepted_at')
                ->first();

            if (!$invitation) {
                return $this->error('Invalid or already used invitation token.', null, 422);
            }

            if ($invitation->isExpired()) {
                return $this->error('This invitation has expired. Please request a new one.', null, 422);
            }

            // Ensure the email matches the invitation
            if (strtolower($invitation->email) !== strtolower($validated['email'])) {
                return $this->error('This invitation was sent to a different email address.', null, 422);
            }

            $user = DB::transaction(function () use ($validated, $invitation) {
                $user = User::create([
                    'firstname' => $validated['firstname'],
                    'surname' => $validated['surname'],
                    'middlename' => $validated['middlename'] ?? null,
                    'email' => $validated['email'],
                    'phone' => $validated['phone'],
                    'password' => Hash::make($validated['password']),
                    'date_of_birth' => $validated['date_of_birth'] ?? null,
                    'gender' => $validated['gender'] ?? null,
                    'email_verified_at' => now(), // ✅ AUTO-VERIFY: User already clicked email link to register
                    // ✅ SIMPLIFIED: onboarding_completed_at is NULL by default = needs onboarding
                    // No need for is_onboarding_force_redirect or onboarding_started_at
                ]);

                // Attach user to the association from the invitation
                $user->associations()->attach($invitation->association_id, [
                    'role' => $invitation->role ?? 'Member', // Keep for backward compatibility
                    'role_id' => $invitation->role_id, // New dynamic role system
                    'status' => 'active',
                    'joined_at' => now(),
                ]);

                // Mark invitation as accepted
                $invitation->update(['accepted_at' => now()]);

                return $user;
            });

            // ✅ NO EMAIL VERIFICATION NEEDED - User already verified by clicking invitation link
            // Auto-login user and redirect to onboarding
            $token = $user->createToken('portal_token', ['access-portal'])->plainTextToken;
            $association = $user->associations()->first();

            return $this->success([
                'user' => $user,
                'token' => $token,
                'token_type' => 'Bearer',
                'association' => $association,
                'needs_onboarding' => true,
                'redirect_to' => config('app.frontend_url') . '/onboarding',
                'message' => 'Registration successful! Complete your profile to get started.',
            ], 'Registration successful! Redirecting to onboarding...', 201);

        } catch (ValidationException $e) {
            return $this->error('Validation failed', $e->errors(), 422);
        } catch (\Exception $e) {
            return $this->error('Registration failed: ' . $e->getMessage(), null, 500);
        }
    }

    /**
     * Verify email with OTP code
     */
    public function verifyEmail(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'email' => 'required|email',
                'code' => 'required|string|size:6',
            ]);

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

            if (!$user) {
                return $this->error('Invalid email address', null, 404);
            }

            $result = $this->emailVerificationService->verifyCode($user, $validated['code']);

            if (!$result['success']) {
                return $this->error($result['message'], null, 422);
            }

            // Issue token now that email is verified
            $user->tokens()->delete();
            $token = $user->createToken('portal_token', ['access-portal'])->plainTextToken;

            return $this->success([
                'user' => $user->fresh(),
                'token' => $token,
                'token_type' => 'Bearer',
            ], 'Email verified successfully');

        } catch (ValidationException $e) {
            return $this->error('Validation failed', $e->errors(), 422);
        } catch (\Exception $e) {
            return $this->error('Verification failed: ' . $e->getMessage(), null, 500);
        }
    }

    /**
     * Resend email verification code
     */
    public function resendVerificationCode(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'email' => 'required|email',
            ]);

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

            if (!$user) {
                // Return success anyway to prevent email enumeration
                return $this->success(null, 'If this email is registered, a verification code has been sent.');
            }

            if ($user->email_verified_at) {
                return $this->error('Email is already verified', null, 422);
            }

            if (!$this->emailVerificationService->canResend($user)) {
                $seconds = $this->emailVerificationService->resendCooldownSeconds($user);
                return $this->error("Please wait {$seconds} seconds before requesting a new code", null, 429);
            }

            $this->emailVerificationService->sendVerificationCode($user);

            return $this->success(null, 'Verification code sent successfully');

        } catch (ValidationException $e) {
            return $this->error('Validation failed', $e->errors(), 422);
        } catch (\Exception $e) {
            return $this->error('Failed to resend code: ' . $e->getMessage(), null, 500);
        }
    }

    /**
     * Login a user
     */
    public function login(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'email' => 'required|email',
                'password' => 'required|string',
                'association_id' => 'nullable|integer',
            ]);

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

            if (!$user || !Hash::check($validated['password'], $user->password)) {
                return $this->error('Invalid credentials', null, 401);
            }

            // Check if email is verified
            if (!$user->email_verified_at) {
                // Send verification link
                $this->emailVerificationService->sendVerificationLink($user);

                return $this->success([
                    'requires_verification' => true,
                    'email' => $user->email,
                    'message' => 'Please check your email and click the verification link to verify your account.',
                ], 'Email verification required. Check your email for the verification link.');
            }

            $associations = $user->associations;

            if ($associations->isEmpty()) {
                return $this->error('User is not associated with any organization', null, 403);
            }

            // Priority 1: Check if association was detected from domain (by middleware)
            $tenantFromDomain = $request->attributes->get('tenant');

            // Priority 2: If association_id is provided, verify membership
            if (isset($validated['association_id'])) {
                $association = $associations->where('id', $validated['association_id'])->first();
                if (!$association) {
                    return $this->error('User does not belong to this association', null, 403);
                }
            } elseif ($tenantFromDomain && $associations->contains($tenantFromDomain)) {
                // Auto-select association from domain
                $association = $tenantFromDomain;
            } else {
                if ($associations->count() === 1) {
                    $association = $associations->first();
                } else {
                    return $this->success([
                        'requires_selection' => true,
                        'associations' => $associations->map(fn ($a) => [
                            'id' => $a->id,
                            'name' => $a->name,
                            'slug' => $a->slug ?? null,
                            'primary_url' => $a->primary_url ?? null,
                        ])->values(),
                    ], 'Please select an association');
                }
            }

            // Update last login
            $user->update(['last_login_at' => now()]);

            // Security: Revoke all previous tokens (Token Rotation)
            $user->tokens()->delete();

            // Issue Scoped Token
            $token = $user->createToken('portal_token', ['access-portal'])->plainTextToken;

            // Check if user has admin access
            $hasAdminAccess = $user->hasAdminRoleInAssociation($association);

            // Check if user needs onboarding
            $needsOnboarding = $this->checkUserNeedsOnboarding($user, $association);

            // Build admin panel URL (only if user has access)
            $adminPanelUrl = null;
            if ($hasAdminAccess) {
                $adminPanelUrl = config('app.url') . '/association/' . $association->slug . '/admin';
            }

            return $this->success([
                'user' => $user,
                'token' => $token,
                'token_type' => 'Bearer',
                'association' => $association,
                'profile_complete' => $user->isProfileComplete(),
                'profile_complete_percentage' => $user->profile_complete_percentage ?? 0,
                'needs_onboarding' => $needsOnboarding,
                'has_admin_access' => $hasAdminAccess,
                'admin_panel_url' => $adminPanelUrl,
                'redirect_to' => $needsOnboarding
                    ? config('app.frontend_url') . '/onboarding'
                    : config('app.frontend_url') . '/dashboard',
            ], 'Login successful');

        } catch (ValidationException $e) {
            return $this->error('Validation failed', $e->errors(), 422);
        } catch (\Exception $e) {
            return $this->error('Internal server error during login', null, 500);
        }
    }

    /**
     * Logout a user
     */
    public function logout(Request $request): JsonResponse
    {
        $request->user()->currentAccessToken()->delete();

        return $this->success(null, 'Logged out successfully');
    }

    /**
     * Get current authenticated user with onboarding status
     */
    public function me(Request $request): JsonResponse
    {
        $user = $request->user()->load(['associations', 'profileFieldValues.profileField']);

        // Get onboarding status
        $association = $user->associations()->first();
        $needsOnboarding = false;
        $onboardingUrl = null;

        if ($association) {
            // Check if user needs onboarding
            $needsOnboarding = $this->checkUserNeedsOnboarding($user, $association);

            if ($needsOnboarding) {
                $frontendUrl = config('app.frontend_url');
                $onboardingUrl = $frontendUrl . '/onboarding?' . http_build_query([
                    'association_id' => $association->id,
                    'association_slug' => $association->slug,
                ]);
            }
        }

        // ✅ BACKEND-DRIVEN: Backend decides where user should be
        $redirectTo = $needsOnboarding
            ? config('app.frontend_url') . '/onboarding'
            : config('app.frontend_url') . '/dashboard';

        return $this->success([
            'user' => $user,
            'profile_complete' => $user->isProfileComplete(),
            'profile_complete_percentage' => $user->profile_complete_percentage ?? 0,
            'needs_onboarding' => $needsOnboarding,
            'redirect_to' => $redirectTo, // ✅ Single source of truth
            'onboarding_url' => $onboardingUrl, // Deprecated, kept for backward compatibility
            'onboarding_completed_at' => $user->onboarding_completed_at,
            'primary_association' => $association ? [
                'id' => $association->id,
                'name' => $association->name,
                'slug' => $association->slug,
            ] : null,
        ], 'User data retrieved successfully');
    }

    /**
     * ✅ SIMPLIFIED: Single source of truth for onboarding status
     * Check if user needs onboarding
     *
     * Logic: User needs onboarding if onboarding_completed_at is NULL
     * This is the ONLY check we need - simple and reliable
     */
    private function checkUserNeedsOnboarding($user, $association): bool
    {
        // ✅ Simple: If onboarding completed globally, no need for onboarding
        if ($user->onboarding_completed_at !== null) {
            return false;
        }

        // ✅ Check association-specific onboarding state
        $onboardingState = $user->onboardingStates()
            ->where('association_id', $association->id)
            ->first();

        if ($onboardingState && $onboardingState->completed_at !== null) {
            return false;
        }

        // ✅ Default: New users need onboarding
        return true;
    }

    /**
     * Refresh token
     */
    public function refreshToken(Request $request): JsonResponse
    {
        $user = $request->user();

        $user->tokens()->delete();

        $token = $user->createToken('portal_token', ['access-portal'])->plainTextToken;

        return $this->success([
            'token' => $token,
            'token_type' => 'Bearer',
        ], 'Token refreshed successfully');
    }

    /**
     * Validate an invitation token (public endpoint for frontend).
     */
    public function validateInvitation(string $token): JsonResponse
    {
        $invitation = Invitation::with('association:id,name,slug')
            ->where('token', $token)
            ->whereNull('accepted_at')
            ->first();

        if (!$invitation) {
            return $this->error('Invalid or already used invitation.', null, 404);
        }

        if ($invitation->isExpired()) {
            return $this->error('This invitation has expired.', null, 410);
        }

        return $this->success([
            'email' => $invitation->email,
            'role' => $invitation->role,
            'association' => $invitation->association ? [
                'id' => $invitation->association->id,
                'name' => $invitation->association->name,
            ] : null,
            'expires_at' => $invitation->expires_at->toIso8601String(),
        ], 'Invitation is valid');
    }

    /**
     * Send password reset link
     */
    public function forgotPassword(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'email' => 'required|email',
            ]);

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

            if ($user) {
                $token = Password::broker()->createToken($user);

                $resetUrl = config('app.frontend_url', 'http://localhost:3000')
                    . '/reset-password?token=' . $token
                    . '&email=' . urlencode($user->email);

                dispatch(new \App\Jobs\SendEmailJob(
                    new \App\Mail\PasswordResetMail($user, $resetUrl, 60),
                    $user->email,
                ));
            }

            // Always return success to prevent email enumeration
            return $this->success(null, 'If this email is registered, a password reset link has been sent.');

        } catch (ValidationException $e) {
            return $this->error('Validation failed', $e->errors(), 422);
        } catch (\Exception $e) {
            return $this->error('Failed to process request: ' . $e->getMessage(), null, 500);
        }
    }

    /**
     * Reset password with token
     */
    public function resetPassword(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'email' => 'required|email',
                'token' => 'required|string',
                'password' => 'required|string|min:8|confirmed',
            ]);

            $status = Password::broker()->reset(
                $request->only('email', 'token', 'password', 'password_confirmation'),
                function (User $user, string $password) {
                    $user->forceFill([
                        'password' => Hash::make($password),
                        'remember_token' => Str::random(60),
                    ])->save();

                    // Revoke all tokens — force re-login
                    $user->tokens()->delete();
                }
            );

            if ($status === Password::PASSWORD_RESET) {
                return $this->success(null, 'Password has been reset successfully. Please log in with your new password.');
            }

            return $this->error('Invalid or expired reset token', null, 422);

        } catch (ValidationException $e) {
            return $this->error('Validation failed', $e->errors(), 422);
        } catch (\Exception $e) {
            return $this->error('Failed to reset password: ' . $e->getMessage(), null, 500);
        }
    }

    /**
     * Verify email via link (click-to-verify)
     */
    public function verifyEmailByLink(Request $request, string $token)
    {
        $result = $this->emailVerificationService->verifyByLink($token);

        if (!$result['success']) {
            // Redirect to frontend with error
            return redirect(config('app.frontend_url') . '/verification-failed?message=' . urlencode($result['message']));
        }

        $user = $result['user'];

        // Get the user's first association
        $association = $user->associations()->first();

        if (!$association) {
            return redirect(config('app.frontend_url') . '/no-association');
        }

        // Create authentication token for frontend
        $token = $user->createToken('auth-token')->plainTextToken;

        // Build frontend onboarding URL with auth token
        $frontendUrl = config('app.frontend_url');
        $onboardingUrl = $frontendUrl . '/onboarding?' . http_build_query([
            'token' => $token,
            'association_id' => $association->id,
            'association_slug' => $association->slug,
            'verified' => 'true',
        ]);

        // Redirect to FRONTEND onboarding page (not Filament backend)
        return redirect($onboardingUrl);
    }
}
