<?php

namespace App\Http\Controllers\Api;

use App\Models\User;
use App\Models\UserDevice;
use App\Models\UserProvider;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use libphonenumber\PhoneNumberUtil;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\PhoneNumberType;
use Carbon\Carbon;
use Dedoc\Scramble\Attributes\HeaderParameter;

/**
 * @tags 02. Authentication  
 */
class AuthController extends ApiController
{
    /**
     * Register User
     * 
     * Register a new regular user account with full profile information.
     * Either email or phone number is required.
     */
    public function register(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'email' => 'nullable|email|unique:users,email',
            'phone' => 'nullable|string|max:20',
            'country_code' => 'nullable|string|max:10',
            'password' => 'required|string|min:6|confirmed',
            'country_id' => 'required|exists:countries,id',
            'language_id' => 'required|exists:languages,id',
            'device_id' => 'required|string|max:255',
            'platform' => 'required|in:android,ios,web',
            'fcm_token' => 'nullable|string',
            'app_version' => 'nullable|string|max:50',
        ]);

        // Ensure at least email or phone is provided
        $validator->after(function ($validator) use ($request) {
            if (!$request->filled('email') && !$request->filled('phone')) {
                $validator->errors()->add('email', 'Either email or phone number is required');
            }
        });

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator->errors());
        }

        return $this->executeTransaction(function () use ($request) {
            $locale = $this->getCurrentLocale($request);
            $deviceInfo = $this->getDeviceInfo($request);

            $userData = [
                'language_id' => $locale['language_id'],
                'country_id' => $locale['country_id'],
                'current_country_id' => $locale['country_id'],
                'name' => $request->name,
                'password' => $request->password,
                'role' => 'user',
                'is_guest' => false,
                'ip_country' => $locale['ip_country'],
            ];

            // Handle email
            if ($request->filled('email')) {
                $userData['email'] = $request->email;
            } else {
                $userData['email'] = Str::uuid() . '@temp.local'; // Temporary email
            }

            // Handle phone number
            if ($request->filled('phone')) {
                $phone = $request->phone;
                $countryCode = $request->country_code;

                try {
                    $phoneUtil = PhoneNumberUtil::getInstance();
                    $proto = $phoneUtil->parse($phone, $countryCode);

                    if (!$phoneUtil->isValidNumber($proto)) {
                        return $this->errorResponse('Invalid phone number', 400);
                    }

                    $numberType = $phoneUtil->getNumberType($proto);
                    if (!in_array($numberType, [PhoneNumberType::MOBILE, PhoneNumberType::FIXED_LINE_OR_MOBILE])) {
                        return $this->errorResponse('Phone number must be mobile', 400);
                    }

                    $e164 = $phoneUtil->format($proto, PhoneNumberFormat::E164);
                    $nationalFormat = $phoneUtil->format($proto, PhoneNumberFormat::NATIONAL);

                    // Check if phone number already exists
                    $existingUser = User::where('e164_number', $e164)->first();
                    if ($existingUser) {
                        return $this->errorResponse('Phone number already exists', 409);
                    }

                    $userData['phone'] = trim($nationalFormat);
                    $userData['e164_number'] = $e164;
                    $userData['country_code'] = $countryCode;
                } catch (\Exception $e) {
                    return $this->errorResponse('Invalid phone number format', 400);
                }
            }

            // Create user
            $user = User::create($userData);

            // Save device information
            UserDevice::updateOrCreate(
                [
                    'user_id' => $user->id,
                    'device_id' => $deviceInfo['device_id'],
                ],
                $deviceInfo
            );

            // Create API Token
            $token = $user->createToken('user-token', ['user'])->plainTextToken;

            $this->logActivity($user, 'user_registered', $deviceInfo);

            return [
                'user' => [
                    'id' => $user->id,
                    'name' => $user->name,
                    'email' => $user->email,
                    'phone' => $user->phone,
                    'country_id' => $user->country_id,
                    'language_id' => $user->language_id,
                    'current_country_id' => $user->current_country_id,
                    'role' => $user->role,
                    'is_guest' => $user->is_guest,
                    'is_verified' => $user->is_verified,
                    'created_at' => $user->created_at,
                ],
                'token' => $token,
                'locale' => $locale,
            ];
        }, 'User registered successfully');
    }

    /**
     * Register Guest User
     * 
     * Register as guest user with device and location information.
     * Guest users have limited functionality and can be upgraded later.
     */
    public function registerGuest(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'country_id' => 'required|exists:countries,id',
            'language_id' => 'required|exists:languages,id',
            'device_id' => 'required|string|max:255',
            'platform' => 'required|in:android,ios,web',
            'fcm_token' => 'nullable|string',
            'app_version' => 'nullable|string|max:50',
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator->errors());
        }

        return $this->executeTransaction(function () use ($request) {
            $locale = $this->getCurrentLocale($request);
            $deviceInfo = $this->getDeviceInfo($request);

            // Create guest user
            $user = User::create([
                'language_id' => $locale['language_id'],
                'country_id' => $locale['country_id'],
                'current_country_id' => $locale['country_id'],
                'name' => 'Guest_' . Str::random(8),
                'email' => Str::uuid() . '@guest.local',
                'password' => Str::random(32), // Random password
                'role' => 'user',
                'is_guest' => true,
                'ip_country' => $locale['ip_country'],
            ]);

            // Save device information
            UserDevice::updateOrCreate(
                [
                    'user_id' => $user->id,
                    'device_id' => $deviceInfo['device_id'],
                ],
                $deviceInfo
            );

            // Create API Token
            $token = $user->createToken('guest-token', ['guest'])->plainTextToken;

            $this->logActivity($user, 'guest_registered', $deviceInfo);

            return [
                'user' => [
                    'id' => $user->id,
                    'name' => $user->name,
                    'email' => $user->email,
                    'phone' => $user->phone,
                    'country_id' => $user->country_id,
                    'language_id' => $user->language_id,
                    'current_country_id' => $user->current_country_id,
                    'role' => $user->role,
                    'is_guest' => $user->is_guest,
                    'is_verified' => $user->is_verified,
                    'created_at' => $user->created_at,
                ],
                'token' => $token,
                'locale' => $locale,
            ];
        }, 'Guest user registered successfully');
    }

    /**
     * Login
     * 
     * Login with email or phone number and password.
     * Updates user location and device information.
     */
    /**
     * Login
     * 
     * Login with email OR phone number and password.
     * Use either email OR phone+country_code, not both.
     */
 public function login(Request $request): JsonResponse
{
    $validator = Validator::make($request->all(), [
        'email' => 'nullable|email',
        'phone' => 'nullable|string',
        'country_code' => 'required_with:phone|string|max:10',
        'password' => 'required|string',
        // إضافة device info
        'device_id' => 'required|string|max:255',
        'platform' => 'required|in:android,ios,web',
        'fcm_token' => 'nullable|string',
        'app_version' => 'nullable|string|max:50',
    ]);

    // Ensure either email OR phone is provided (not both)
    $validator->after(function ($validator) use ($request) {
        $hasEmail = $request->filled('email');
        $hasPhone = $request->filled('phone');

        if (!$hasEmail && !$hasPhone) {
            $validator->errors()->add('email', 'Either email or phone number is required');
        }

        if ($hasEmail && $hasPhone) {
            $validator->errors()->add('email', 'Use either email or phone, not both');
        }
    });

    if ($validator->fails()) {
        return $this->validationErrorResponse($validator->errors());
    }

    $password = $request->password;
    $user = null;

    // Find user by email OR phone
    if ($request->filled('email')) {
        // Login with email
        $user = User::where('email', $request->email)->first();
    } else {
        // Login with phone
        $phone = $request->phone;
        $countryCode = $request->country_code;

        try {
            $phoneUtil = PhoneNumberUtil::getInstance();
            $proto = $phoneUtil->parse($phone, $countryCode);

            if ($phoneUtil->isValidNumber($proto)) {
                $e164 = $phoneUtil->format($proto, PhoneNumberFormat::E164);
                $user = User::where('e164_number', $e164)->first();
            } else {
                return $this->errorResponse('Invalid phone number', 400);
            }
        } catch (\Exception $e) {
            return $this->errorResponse('Invalid phone number format', 400);
        }
    }

    if (!$user) {
        return $this->errorResponse('Invalid credentials', 401);
    }

    // Check password
    if (!Hash::check($password, $user->password)) {
        return $this->errorResponse('Invalid credentials', 401);
    }

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

    // Save/Update device information
    $deviceInfo = [
        'device_id' => $request->device_id,
        'platform' => $request->platform,
        'app_version' => $request->app_version,
        'fcm_token' => $request->fcm_token,
        'last_ip' => $request->ip(),
        'user_agent' => $request->userAgent(),
        'last_seen' => now(),
    ];

    $device = UserDevice::updateOrCreate(
        [
            'user_id' => $user->id,
            'device_id' => $request->device_id,
        ],
        $deviceInfo
    );

    // Create API Token مربوط بالـ device
    $abilities = $user->is_guest ? ['guest'] : ['user'];
    $tokenName = ($user->is_guest ? 'guest-token' : 'user-token') . '-' . $request->device_id;
    $token = $user->createToken($tokenName, $abilities)->plainTextToken;

    return $this->successResponse([
        'user' => [
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
            'phone' => $user->phone,
            'country_id' => $user->country_id,
            'language_id' => $user->language_id,
            'role' => $user->role,
            'is_guest' => $user->is_guest,
            'is_verified' => $user->is_verified,
            'last_login_at' => $user->last_login_at,
        ],
        'token' => $token,
        'device' => [
            'device_id' => $request->device_id,
            'platform' => $request->platform,
            'is_new_device' => $device->wasRecentlyCreated, // هل الجهاز جديد؟
            'last_seen' => $device->last_seen,
        ],
    ], 'Login successful');
}

    /**
     * Social Login
     * 
     * Login with social media provider (Google, Facebook, Twitter, Apple).
     * Creates new user if doesn't exist.
     */
    public function socialLogin(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'provider' => 'required|in:google,facebook,twitter,apple',
            'provider_token' => 'required|string',
            'country_id' => 'nullable|exists:countries,id',
            'language_id' => 'nullable|exists:languages,id',
            'device_id' => 'required|string|max:255',
            'platform' => 'required|in:android,ios,web',
            'fcm_token' => 'nullable|string',
            'app_version' => 'nullable|string|max:50',
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator->errors());
        }

        return $this->executeTransaction(function () use ($request) {
            $provider = $request->provider;
            $providerToken = $request->provider_token;

            // Verify provider token and get user data
            $providerUser = $this->verifyProviderToken($provider, $providerToken);

            if (!$providerUser) {
                return $this->errorResponse('Invalid provider token', 401);
            }

            $locale = $this->getCurrentLocale($request);
            $deviceInfo = $this->getDeviceInfo($request);

            // Check if user exists by provider ID
            $userProvider = UserProvider::where('provider', $provider)
                ->where('provider_id', $providerUser['id'])
                ->first();

            if ($userProvider) {
                $user = $userProvider->user;
            } else {
                // Check if user exists by email
                $user = User::where('email', $providerUser['email'])->first();

                if (!$user) {
                    // Create new user
                    $user = User::create([
                        'language_id' => $locale['language_id'],
                        'country_id' => $locale['country_id'],
                        'current_country_id' => $locale['country_id'],
                        'name' => $providerUser['name'],
                        'email' => $providerUser['email'],
                        'password' => Str::random(32), // Random password
                        'role' => 'user',
                        'is_guest' => false,
                        'is_verified' => $providerUser['email_verified'] ?? false,
                        'ip_country' => $locale['ip_country'],
                    ]);
                }

                // Create provider record
                UserProvider::create([
                    'user_id' => $user->id,
                    'provider' => $provider,
                    'provider_id' => $providerUser['id'],
                    'provider_email' => $providerUser['email'],
                ]);
            }

            // Update user information
            $user->update([
                'current_country_id' => $locale['country_id'],
                'ip_country' => $locale['ip_country'],
                'last_login_at' => now(),
            ]);

            // Save device information
            UserDevice::updateOrCreate(
                [
                    'user_id' => $user->id,
                    'device_id' => $deviceInfo['device_id'],
                ],
                $deviceInfo
            );

            // Create API Token
            $abilities = $user->is_guest ? ['guest'] : ['user'];
            $token = $user->createToken('social-auth-token', $abilities)->plainTextToken;

            $this->logActivity($user, 'social_login', array_merge($deviceInfo, ['provider' => $provider]));

            return [
                'user' => [
                    'id' => $user->id,
                    'name' => $user->name,
                    'email' => $user->email,
                    'phone' => $user->phone,
                    'country_id' => $user->country_id,
                    'language_id' => $user->language_id,
                    'current_country_id' => $user->current_country_id,
                    'role' => $user->role,
                    'is_guest' => $user->is_guest,
                    'is_verified' => $user->is_verified,
                    'last_login_at' => $user->last_login_at,
                ],
                'token' => $token,
                'locale' => $locale,
            ];
        }, 'Social login successful');
    }

    /**
     * Forgot Password
     * 
     * Send OTP code for password reset via email or SMS.
     */
    public function forgotPassword(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'identifier' => 'required|string',
            'country_code' => 'nullable|string|max:10',
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator->errors());
        }

        return $this->executeTransaction(function () use ($request) {
            $identifier = $request->identifier;
            $countryCode = $request->country_code;

            // Find user
            $user = $this->findUserByIdentifier($identifier, $countryCode);

            if (!$user) {
                return $this->errorResponse('User not found', 404);
            }

            // Generate OTP
            $otpCode = str_pad(random_int(100000, 999999), 6, '0', STR_PAD_LEFT);
            $expiresAt = now()->addMinutes(10);

            // Update user with OTP
            $user->update([
                'otp_code' => $otpCode,
                'otp_expires_at' => $expiresAt,
                'otp_verified_at' => null,
                'otp_attempts' => 0,
            ]);

            // Send OTP
            $this->sendOTP($user, $otpCode);

            $this->logActivity($user, 'password_reset_requested', ['identifier' => $identifier]);

            return [
                'message' => 'OTP code sent successfully',
                'expires_at' => $expiresAt->toISOString(),
            ];
        }, 'OTP sent successfully');
    }

    /**
     * Verify OTP
     * 
     * Verify the 6-digit OTP code sent for password reset.
     */
    public function verifyOTP(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'identifier' => 'required|string',
            'otp_code' => 'required|string|size:6',
            'country_code' => 'nullable|string|max:10',
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator->errors());
        }

        $identifier = $request->identifier;
        $otpCode = $request->otp_code;
        $countryCode = $request->country_code;

        // Find user
        $user = $this->findUserByIdentifier($identifier, $countryCode);

        if (!$user) {
            return $this->errorResponse('User not found', 404);
        }

        // Verify OTP
        if (!$user->otp_code || $user->otp_code !== $otpCode) {
            $user->increment('otp_attempts');
            return $this->errorResponse('Invalid OTP code', 400);
        }

        if ($user->otp_expires_at && $user->otp_expires_at->isPast()) {
            return $this->errorResponse('OTP code has expired', 400);
        }

        // Mark as verified
        $user->update([
            'otp_verified_at' => now(),
        ]);

        $this->logActivity($user, 'otp_verified', ['identifier' => $identifier]);

        return $this->successResponse([
            'verified' => true,
            'verified_at' => $user->otp_verified_at->toISOString(),
        ], 'OTP verified successfully');
    }

    /**
     * Reset Password
     * 
     * Reset user password using verified OTP code.
     * All user sessions will be logged out after password reset.
     */
    public function resetPassword(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'identifier' => 'required|string',
            'otp_code' => 'required|string|size:6',
            'new_password' => 'required|string|min:6|confirmed',
            'country_code' => 'nullable|string|max:10',
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator->errors());
        }

        return $this->executeTransaction(function () use ($request) {
            $identifier = $request->identifier;
            $otpCode = $request->otp_code;
            $newPassword = $request->new_password;
            $countryCode = $request->country_code;

            // Find user
            $user = $this->findUserByIdentifier($identifier, $countryCode);

            if (!$user) {
                return $this->errorResponse('User not found', 404);
            }

            // Verify OTP
            if (!$user->otp_code || $user->otp_code !== $otpCode) {
                return $this->errorResponse('Invalid OTP code', 400);
            }

            if ($user->otp_expires_at && $user->otp_expires_at->isPast()) {
                return $this->errorResponse('OTP code has expired', 400);
            }

            if (!$user->otp_verified_at || $user->otp_verified_at->diffInMinutes(now()) > 10) {
                return $this->errorResponse('OTP not verified or verification expired', 400);
            }

            // Update password
            $user->update([
                'password' => $newPassword, // Will be hashed in model
                'otp_code' => null,
                'otp_expires_at' => null,
                'otp_verified_at' => null,
                'otp_attempts' => 0,
            ]);

            // Revoke all tokens
            $user->tokens()->delete();

            $this->logActivity($user, 'password_reset', ['identifier' => $identifier]);

            return [
                'message' => 'Password reset successfully',
                'reset_at' => now()->toISOString(),
            ];
        }, 'Password reset successfully');
    }

    /**
     * Logout
     * 
     * Logout from current session only.
     * Requires Bearer token authentication.
     */
    #[HeaderParameter('Authorization', 'Bearer {token} for authentication', required: true, type: 'string', example: 'Bearer 1|f832abc...xyz')]
    public function logout(Request $request): JsonResponse
    {
        try {
            // Delete current token
            $request->user()->currentAccessToken()->delete();

            return $this->successResponse(null, 'Logged out successfully');
        } catch (\Exception $e) {
            return $this->errorResponse('Logout failed', 500);
        }
    }

    /**
     * Logout All
     * 
     * Logout from all devices and sessions.
     * Requires Bearer token authentication.
     */
    #[HeaderParameter('Authorization', 'Bearer {token} for authentication', required: true, type: 'string', example: 'Bearer 1|f832abc...xyz')]
    public function logoutAll(Request $request): JsonResponse
    {
        try {
            // Delete all tokens for this user
            $request->user()->tokens()->delete();

            return $this->successResponse(null, 'Logged out from all devices successfully');
        } catch (\Exception $e) {
            return $this->errorResponse('Logout failed', 500);
        }
    }

    // Helper Methods

    /**
     * Find user by email or phone
     */
    private function findUserByIdentifier($identifier, $countryCode = null)
    {
        // Check if email
        if (filter_var($identifier, FILTER_VALIDATE_EMAIL)) {
            return User::where('email', $identifier)->first();
        }

        // Check if phone number
        try {
            $phoneUtil = PhoneNumberUtil::getInstance();
            $proto = $phoneUtil->parse($identifier, $countryCode);

            if ($phoneUtil->isValidNumber($proto)) {
                $e164 = $phoneUtil->format($proto, PhoneNumberFormat::E164);
                return User::where('e164_number', $e164)->first();
            }
        } catch (\Exception $e) {
            // If phone parsing fails, try direct search
            return User::where('phone', $identifier)->first();
        }

        return null;
    }

    /**
     * Verify provider token (simple example)
     */
    private function verifyProviderToken($provider, $token)
    {
        // This is a simple example - in reality you'd verify with provider APIs
        // like Google OAuth API, Facebook Graph API, etc.

        return [
            'id' => 'provider_user_' . substr($token, 0, 8),
            'name' => 'Social User',
            'email' => 'user@' . $provider . '.com',
            'email_verified' => true,
        ];
    }

    /**
     * Send OTP
     */
    private function sendOTP($user, $otpCode)
    {
        // Here you would implement OTP sending via Email or SMS
        // Example:
        // Mail::to($user->email)->send(new OTPMail($otpCode));
        // or SMS::to($user->phone)->send("Your OTP: {$otpCode}");

        // For development, log the OTP
        \Log::info("OTP Code for user {$user->id}: {$otpCode}");
    }
}
