<?php

namespace App\Http\Controllers;

use Exception;
use Carbon\Carbon;
use App\Models\User;
use App\Mail\ResetPinMail;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Laravel\Socialite\Facades\Socialite;
use App\Http\Resources\UserShortResource;
use Illuminate\Support\Facades\Validator;

class AuthController extends Controller
{


    public function showLogin()
    {

        return view('front_end.pages.auth.login');
    }

    public function showRegister()
    {
        return view('front_end.pages.auth.register');
    }
    public function webRegister(Request $request)
    {
        if (setting('user_registration') == 0) {
            return redirect()->route('register')->with('error', 'User registration is disabled');
        }

        // Validate user input
        $passwordRules = ['required', 'string', 'min:8', 'max:255', 'confirmed'];

        // Add password complexity rules if enabled
        if (setting('password_complexity') == 1) {
            $passwordRules[] = 'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/';
        }

        $validator = Validator::make($request->all(), [
            'email' => 'required|email|unique:users,email',
            'password' => $passwordRules,
            'first_name' => 'required|string|max:125',
            'last_name' => 'required|string|max:125',
            'gender' => 'required|in:Male,Female',
            'date_of_birth' => 'nullable|date',
        ]);

        // Add custom error message for password complexity
        if (setting('password_complexity') == 1) {
            $validator->addCustomAttributes([
                'password' => 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character.'
            ]);
        }

        // If validation fails, redirect back with errors
        if ($validator->fails()) {
            return back()->withErrors($validator)->withInput();
        }

        // Validate reCAPTCHA if enabled
        if (setting('recaptcha') == 1) {
            $recaptchaSecret = setting('recaptcha_secret');
            $recaptchaResponse = $request->input('g-recaptcha-response');

            if (!$recaptchaResponse) {
                return back()->withErrors(['recaptcha' => 'Please complete the reCAPTCHA verification.'])->withInput();
            }

            // Verify reCAPTCHA with Google using cURL
            $recaptchaUrl = 'https://www.google.com/recaptcha/api/siteverify';
            $recaptchaData = [
                'secret' => $recaptchaSecret,
                'response' => $recaptchaResponse,
                'remoteip' => $request->ip()
            ];

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $recaptchaUrl);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($recaptchaData));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

            $recaptchaResult = curl_exec($ch);
            curl_close($ch);

            $recaptchaResult = json_decode($recaptchaResult, true);

            if (!$recaptchaResult['success']) {
                return back()->withErrors(['recaptcha' => 'reCAPTCHA verification failed. Please try again.'])->withInput();
            }
        }

        // Generate a unique username
        if (setting('auto_username') == 1) {
            $emailParts = explode('@', $request->email);
            $username = User::where('username', $emailParts[0])->exists() ? $emailParts[0] . rand(100, 999) : $emailParts[0];
        } else {
            $username = User::where('username', $request->username)->exists() ? $request->username . rand(100, 999) : $request->username;
        }

        // Assign a default avatar based on gender
        $randNum = rand(1, 4);
        $avatar = $request->gender === "Female" ? 'img/placeholder/female_{$randNum}.jpg' :  'img/placeholder/male_{$randNum}.jpg';

        // Get device details
        $deviceType = "Web"; // Web-based registration
        $deviceId = $request->header('User-Agent'); // Capturing browser info as device_id
        $lastIp = $request->ip(); // Capturing user's IP address


        // Create the user
        $user = User::create([
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'name' => $request->first_name . ' ' . $request->last_name, // Full name
            'email' => $request->email,
            'password' => Hash::make($request->password),
            'username' => $username,
            'avatar' => $avatar,
            'gender' => $request->gender,
            'date_of_birth' => $request->date_of_birth,
            'status' => 1, // Mark active upon registration
            'last_seen' => now(),
            'device_type' => $deviceType,
            'device_id' => $deviceId,
            'last_ip' => $lastIp,
            'login_count' => 0, // Initialize login count
        ]);

        // Log the user in
        Auth::login($user);

        // Redirect to the newsfeed with a success message
        return redirect()->route('newsfeed')->with('success', 'Registration successful! Welcome to SocialLink.');
    }



    public function showForgot()
    {
        return view('front_end.pages.auth.forgot_password');
    }

    public function webLogin(Request $request)
    {
        // Validate user input
        $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        $credentials = $request->only('email', 'password');
        $remember = $request->has('remember'); // Remember me functionality

        // Attempt to authenticate user with 'status' check
        if (Auth::attempt(['email' => $credentials['email'], 'password' => $credentials['password'], 'status' => 1], $remember)) {
            session()->regenerate(); // Prevent session fixation attack

            return redirect()->route('newsfeed')->with('success', 'Login successful!');
        }

        // Redirect back with input and error message
        return back()->withInput()->withErrors(['email' => 'Invalid email or password.']);
    }



    /**
     * Handle API login request.
     */
    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email',
            'password' => 'required',
            'device_id' => 'required'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status' => 422,
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], 422);
        }

        $credentials = $request->only('email', 'password');


        // API authentication using Laravel Sanctum
        if (Auth::attempt($credentials)) {
            $user = Auth::user();
            $user->device_id = $request->device_id;
            $user->update();
            // Ensure the user is active
            if ($user->status !== 1) {
                return response()->json(['status' => 403, 'message' => 'Account is inactive.'], 403);
            }

            // ✅ Create Sanctum token for API authentication
            $token = $user->createToken('API Token')->plainTextToken;
            //$token = $user->createToken('API Token', ['*'], Carbon::now()->format('Y-m-d H:i:s'))->plainTextToken;;

            return response()->json([
                'status' => 200,
                'message' => 'Login successful (API Auth)',
                'token' => $token,
                'data' => new UserResource($user),
            ], 200);
        }
        return response()->json(['status' => 401, 'message' => 'Invalid credentials.'], 401);
    }





    public function registerApi(Request $request)
    {
        if (setting('user_registration') == 0) {
            return response()->json([
                'status' => 409,
                'message' => 'User registration is disabled',
            ], 409);
        }

        // Prepare password validation rules
        $passwordRules = ['required', 'string', 'min:8', 'max:255'];

        // Add password complexity rules if enabled
        if (setting('password_complexity') == 1) {
            $passwordRules[] = 'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/';
        }

        $validator = Validator::make($request->all(), [
            'email' => ['required', 'email', 'unique:users,email'],
            'password' => $passwordRules,
            'password_confirm' => ['required', 'same:password'],
            'gender' =>  'nullable|in:Male,Female',
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'device_id' => 'nullable|string|max:255',
            'device_type' => 'nullable|string|max:255',
            'date_of_birth' => 'nullable|date',
        ]);

        // Add custom error message for password complexity
        if (setting('password_complexity') == 1) {
            $validator->addCustomAttributes([
                'password' => 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character.'
            ]);
        }

        if ($validator->fails()) {
            return response()->json([
                'status' => 409,
                'message' => $validator->errors()->first(),
                'errors' => $validator->errors(),
            ], 409);
        }

        $randNum = rand(1, 4);
        $avatar = $request->gender === "Female" ? 'uploads/placeholder/avatar-f1.png' : "uploads/placeholder/avatar-{$randNum}.png";

        $emailParts = explode('@', $request->email);
        $username = User::where('username', $emailParts[0])->exists() ? $emailParts[0] . rand(100, 999) : $emailParts[0];

        $userData = [
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
            'username' => $username,
            'avatar' => $avatar,
            'gender' => $request->gender ?? 'Male',
            'device_id' => $request->device_id,
            'device_type' => $request->device_type,
            'date_of_birth' => $request->date_of_birth,
            'last_seen' => now(),
        ];

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

        // Generate a token for the newly registered user
        $token = $user->createToken('API Token')->plainTextToken;

        // Return the same format as the login response
        return response()->json([
            'status' => 200,
            'message' => __('Api.registration_success'),
            'token' => $token,
            'data' => new UserResource($user),
        ], 200);
    }
    public function socialLogin()
    {
        $providerUser = null;
        $accessToken = request()->get('access_token');
        $provider = request()->get('provider');

        try {
            $providerUser = Socialite::driver($provider)->userFromToken($accessToken);
        } catch (Exception $exception) {
            return response()->json(['status' => 400, 'message' => 'Social login failed' . $exception->getMessage()], 200);
        }
        if ($providerUser) {

            $user = User::where('email', $providerUser->getEmail())->first();
            // checking the user if already exist
            if (empty($user)) {
                $imageContent = file_get_contents($providerUser->getAvatar());
                $uploadPath = public_path('uploads/profile_image/');

                // Ensure the directory exists
                if (!File::exists($uploadPath)) {
                    File::makeDirectory($uploadPath, 0777, true, true);
                }

                // 5. Generate unique filename
                $imageName = uniqid() . '.jpg';
                $imagePath = $uploadPath . $imageName;

                file_put_contents($imagePath, $imageContent);
                $full_name = $providerUser->getName();
                $username = explode('@', $providerUser->getEmail())[0];
                $name_parts = explode(' ', $full_name);
                $first_name = $name_parts[0];
                $last_name = end($name_parts);
                $password =  rand(10000, 99999) . time();
                $user = new User;
                $user->first_name = $first_name;
                $user->last_name = $last_name;
                $user->email = $providerUser->getEmail();
                $user->password = $password;
                $user->email_verified_at = now();
                $user->username = $username;
                $user->device_type = $request->device_type ?? '';
                $user->device_id = $request->device_id ?? '';
                $user->avatar = 'uploads/profile_image/' . $imageName;
                $user->notification_setting = '{"notify_like": 1, "notify_comment": 1, "notify_share_post": 1, "notify_accept_request": 1, "notify_liked_page": 1, "notify_joined_group": 1, "notify_view_story": 1, "notify_visited_my_profile": 0, "notify_mentioned_me": 1, "notify_message": 1, "notify_friends_newpost": 1, "notify_profile_visit": 1, "notify_send_request": 1}';
                $user->save();
            }

            if (empty($user->email_verified_at)) {
                $user->email_verified_at = now();
                $user->update();
            }
            $token =  $user->createToken('MyApp')->plainTextToken;


            return response()->json([
                'status' => 200,
                'message' => __('Api.registration_success'),
                'token' => $token,
                'data' => new UserResource($user),
            ], 200);
        }
    }


    protected function sendEmailVerification(User $user)
    {
        try {
            $verificationToken = Str::random(64);

            // Save the verification token
            DB::table('email_verifications')->updateOrInsert(
                ['user_id' => $user->id],
                [
                    'token' => $verificationToken,
                    'created_at' => now(),
                ]
            );

            // Send email (pseudo-code, replace with your actual mail implementation)
            Mail::send('emails.verify', ['token' => $verificationToken], function ($message) use ($user) {
                $message->to($user->email);
                $message->subject('Verify Your Email');
            });

            return true;
        } catch (\Exception $e) {

            return false;
        }
    }


    /**
     * Handle API logout request.
     */
    public function logout(Request $request)
    {
        $user = $request->user();

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

        return response()->json(['status' => 200, 'message' => 'Logout successful.'], 200);
    }

    /**
     * Protected Route Example
     */
    public function userDetails(Request $request)
    {
        return response()->json($request->user(), 200);
    }


    /**
     * Handle the password reset PIN request.
     */
    public function xxxrequestPasswordResetPin(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email|exists:users,email',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status' => 422,
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], 422);
        }

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

        // Generate a secure numeric PIN (6 digits)
        $pin = random_int(100000, 999999);

        // Store the PIN in the database with expiration
        DB::table('password_reset_pins')->updateOrInsert(
            ['user_id' => $user->id],
            [
                'pin' => Hash::make($pin),
                'expires_at' => now()->addHour(),
                'updated_at' => now(),
                'created_at' => now(),
            ]
        );

        try {
            // Send the PIN to the user's email 
            Mail::to($user->email)->send(new ResetPinMail($pin));
        } catch (\Exception $e) {
            return response()->json([
                'status' => 500,
                'message' => 'Failed to send reset PIN. Please try again later.',
            ], 500);
        }

        return response()->json([
            'status' => 200,
            'message' => 'Password reset PIN sent successfully.',
        ], 200);
    }

    /**
     * Handle the password reset using PIN.
     */
    public function resetPasswordUsingPin(Request $request)
    {
        // Prepare password validation rules
        $passwordRules = ['required', 'string', 'min:8', 'max:255', 'confirmed'];

        // Add password complexity rules if enabled
        if (setting('password_complexity') == 1) {
            $passwordRules[] = 'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/';
        }

        $validator = Validator::make($request->all(), [
            'email' => 'required|email|exists:users,email',
            'pin' => 'required|digits:6',
            'password' => $passwordRules,
        ]);

        // Add custom error message for password complexity
        if (setting('password_complexity') == 1) {
            $validator->addCustomAttributes([
                'password' => 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character.'
            ]);
        }

        if ($validator->fails()) {
            return response()->json([
                'status' => 422,
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], 422);
        }

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

        // Retrieve and validate the PIN
        $pinRecord = DB::table('password_reset_pins')
            ->where('user_id', $user->id)
            ->where('expires_at', '>', now())
            ->first();

        if (!$pinRecord || !Hash::check($request->pin, $pinRecord->pin)) {
            return response()->json([
                'status' => 403,
                'message' => 'Invalid or expired PIN.',
            ], 403);
        }

        // Update the user's password
        $user->update([
            'password' => Hash::make($request->password),
        ]);

        // Delete the used PIN
        DB::table('password_reset_pins')->where('user_id', $user->id)->delete();

        return response()->json([
            'status' => 200,
            'message' => 'Password updated successfully.',
        ], 200);
    }

    public function requestPasswordResetPin(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email|exists:users,email',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status' => 422,
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], 422);
        }

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

        // Check if the user has requested a PIN recently
        $pinRecord = DB::table('password_reset_pins')->where('user_id', $user->id)->first();

        if ($pinRecord && $pinRecord->last_requested_at) {
            $lastRequested = \Carbon\Carbon::parse($pinRecord->last_requested_at);
            if ($lastRequested->diffInSeconds(now()) < 60) {
                return response()->json([
                    'status' => 429, // Too Many Requests
                    'message' => 'You can request a new PIN after 1 minute.',
                ], 429);
            }
        }

        // Generate a secure numeric PIN (6 digits)
        $pin = random_int(100000, 999999);

        // Update or insert the PIN record
        DB::table('password_reset_pins')->updateOrInsert(
            ['user_id' => $user->id],
            [
                'pin' => Hash::make($pin),
                'expires_at' => now()->addHour(),
                'last_requested_at' => now(),
                'updated_at' => now(),
                'created_at' => now(),
            ]
        );

        try {
            // Send the PIN to the user's email (pseudo-code)
            Mail::to($user->email)->send(new ResetPinMail($pin));
        } catch (\Exception $e) {
            return response()->json([
                'status' => 500,
                'message' => 'Failed to send reset PIN. Please try again later.' . 'pincode=>' . $pin,
            ], 500);
        }

        return response()->json([
            'status' => 200,
            'message' => 'Password reset PIN sent successfully.',
        ], 200);
    }


    // Fetch all sessions for the currently authenticated user
    public function getSessions()
    {
        $userId = auth()->id();

        $sessions = DB::table('sessions')
            ->where('user_id', $userId)
            ->orderByDesc('id')
            ->get();

        return response()->json([
            'code' => 200,
            'message' => 'Sessions fetched successfully',
            'data' => $sessions,
        ], 200);
    }

    // Delete a specific session for the currently authenticated user
    public function deleteSession(Request $request)
    {
        $request->validate([
            'session_id' => 'required|exists:sessions,id',
        ]);

        $userId = auth()->id();
        $sessionId = $request->input('session_id');

        $session = DB::table('sessions')
            ->where('id', $sessionId)
            ->first();

        if (!$session) {
            return response()->json([
                'code' => 404,
                'message' => 'Session not found',
            ], 404);
        }

        if ($session->user_id !== $userId) {
            return response()->json([
                'code' => 403,
                'message' => 'You are not allowed to delete this session',
            ], 403);
        }

        DB::table('sessions')
            ->where('id', $sessionId)
            ->delete();

        return response()->json([
            'code' => 200,
            'message' => 'Session deleted successfully',
        ], 200);
    }
}
