<?php

namespace App\Http\Controllers\Api\User;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Api\Traits\ApiResponse;
use App\Http\Requests\Api\User\LoginUserRequest;
use App\Http\Requests\Api\User\RecoverUserPasswordRequest;
use App\Http\Requests\Api\User\RegisterUserRequest;
use App\Http\Requests\Api\User\ResetUserPasswordRequest;
use App\Http\Resources\UserResource;
use App\Models\User;
use App\Notifications\ForgetPasswordEmailNotification;
use App\Notifications\ForgetPasswordSMSNotification;
use App\Notifications\NewUserConfirmEmailNotification;
use App\Services\SmsService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class UserAuthController extends Controller
{
    use ApiResponse;

    public function __construct(private SmsService $smsService) {}

    /**
     * @OA\Post(
     *     path="/api/user/register",
     *     summary="Register a new user",
     *     tags={"User Authentication"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *      @OA\Parameter(
     *        name="firebase_token",
     *        in="header",
     *        required=false,
     *        description="Firebase token for push notifications",
     *        @OA\Schema(type="string")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"first_name", "last_name", "email", "phone", "password", "password_confirmation"},
     *             @OA\Property(property="first_name", type="string", example="John"),
     *             @OA\Property(property="last_name", type="string", example="Doe"),
     *             @OA\Property(property="email", type="string", format="email", example="user@example.com"),
     *             @OA\Property(property="phone", type="string", example="966512345678"),
     *             @OA\Property(property="password", type="string", format="password", example="password"),
     *             @OA\Property(property="password_confirmation", type="string", format="password", example="password")
     *         )
     *     ),
     *     @OA\Response(
     *         response=201,
     *         description="User registered successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object",
     *                 @OA\Property(property="user", ref="#/components/schemas/UserResource"),
     *                 @OA\Property(property="token", type="string")
     *             ),
     *             @OA\Property(property="message", type="string", example="User registered successfully.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=422,
     *         description="Validation error"
     *     )
     * )
     */
    public function register(RegisterUserRequest $request)
    {
        $user = User::create($request->validated());

        $token = $user->createToken('auth_token')->plainTextToken;
        if ($request->header('x-firebase-token')) {
            $user->firebase_token = $request->header('x-firebase-token');
            $user->save();
        }
        if ($request->header('Accept-Language')) {
            $user->pref_lang = $request->header('Accept-Language');
            $user->save();
        }

        $code = strval(rand(1000, 9999));
        if (!app()->isProduction()) {
            $code = "0000";
        }
        DB::table('password_reset_tokens')->updateOrInsert(
            ['email' => $request->email],
            [
                'token' => Hash::make($code),
                'created_at' => Carbon::now()
            ]
        );
        $user->notify(new NewUserConfirmEmailNotification($user->name, $user->email, $code));

        return $this->successResponse([
            'user' => new UserResource($user),
            'token' => $token,
        ], __('messages.user_registered_successfully'), 201);
    }

    /**
     * @OA\Post(
     *     path="/api/user/login",
     *     summary="Login a user",
     *     tags={"User Authentication"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *      @OA\Parameter(
     *        name="firebase_token",
     *        in="header",
     *        required=false,
     *        description="Firebase token for push notifications",
     *        @OA\Schema(type="string")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"email", "password"},
     *             @OA\Property(property="email", type="string", example="user@example.com or 966512345678", description="User's email or phone number"),
     *             @OA\Property(property="password", type="string", format="password", example="password")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="User logged in successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object",
     *                 @OA\Property(property="user", ref="#/components/schemas/UserResource"),
     *                 @OA\Property(property="token", type="string")
     *             ),
     *             @OA\Property(property="message", type="string", example="Login successful.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=401,
     *         description="Invalid credentials"
     *     )
     * )
     */
    public function login(LoginUserRequest $request)
    {
        $credentials = $request->only('email', 'password');
        $user = User::where('email', $request->email)
            ->orWhere('phone', $request->email)
            ->scopes(['active'])
            ->first();
        if ($user) {

            if (! Hash::check($request->password, $user->password)) {
                return $this->errorResponse(__('messages.incorrect_password'));
            }
            if ($request->header('x-firebase-token')) {
                $user->firebase_token = $request->header('x-firebase-token');
                $user->save();
            }
            if ($request->header('Accept-Language')) {
                $user->pref_lang = $request->header('Accept-Language');
                $user->save();
            }

            $token = $user->createToken('auth_token')->plainTextToken;

            return $this->successResponse([
                'user' => new UserResource($user),
                'token' => $token,
            ], __('messages.user_logged_in_successfully'));
        }

        return $this->errorResponse(__('auth.failed'), 401);
    }

    /**
     * @OA\Post(
     *     path="/api/user/password/forgot",
     *     summary="Forgot user password",
     *     tags={"User Authentication"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"email"},
     *             @OA\Property(property="email", type="string", example="user@example.com or 966512345678", description="User's email or phone number")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Password recovery token sent",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="Password reset token sent.")
     *         )
     *     )
     * )
     */
    public function forgotPassword(RecoverUserPasswordRequest $request)
    {
        $user = User::where('email', $request->email)
            ->orWhere('phone', $request->email)
            ->scopes(['active'])
            ->first();

        if (!$user) {
            return $this->errorResponse(__('passwords.user'), 400);
        }

        $token = strval(rand(1000, 9999));
        if (!app()->isProduction()) {
            $token = "0000";
        }
        DB::table('password_reset_tokens')->updateOrInsert(
            ['email' => $request->email],
            [
                'token' => Hash::make($token),
                'created_at' => Carbon::now()
            ]
        );
        if ($request->email == $user->phone) {
            if (app()->isProduction())
                $this->smsService->send($user->phone, "Your OTP is: {$token}");
            // $user->notify(new ForgetPasswordSMSNotification($user->name, $user->phone, $token));
        } else {
            $user->notify(new ForgetPasswordEmailNotification($user->name, $user->email, $token));
        }
        // In a real application, you would send an email or SMS with the token.
        // For this implementation, we will return the token in the response for simplicity.
        return $this->successResponse(null, __('passwords.sent'));
    }

    /**
     * @OA\Post(
     *     path="/api/user/password/reset",
     *     summary="Reset user password",
     *     tags={"User Authentication"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"email", "token"},
     *             @OA\Property(property="email", type="string", example="user@example.com or 966512345678", description="User's email or phone number"),
     *             @OA\Property(property="token", type="string", example="123456")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Password has been reset",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object",
     *                 @OA\Property(property="access_token", type="string"),
     *                 @OA\Property(property="token_type", type="string", example="Bearer"),
     *                 @OA\Property(property="provider", ref="#/components/schemas/UserResource")
     *             ),
     *             @OA\Property(property="message", type="string", example="Password reset successful.")
     *         )
     *     )
     * )
     */
    public function resetPassword(ResetUserPasswordRequest $request)
    {

        $resetRecord = DB::table('password_reset_tokens')
            ->where('email', $request->email)
            ->first();

        if (!$resetRecord) {
            return $this->errorResponse(__('messages.invalid_token'), 400);
        }
        if (!Hash::check($request->token, $resetRecord->token)) {
            return $this->errorResponse(__('messages.invalid_token'), 400);
        }

        // if passes 10 minutes
        if (Carbon::now()->diffInMinutes($resetRecord->created_at) > 10) {
            return $this->errorResponse(__('messages.token_expired'), 400);
        }

        $user = User::where('email', $request->email)
            ->scopes(['active'])
            ->orWhere('phone', $request->email)
            ->first();
        if (!$user) {
            return $this->errorResponse(__('messages.user_not_found'), 404);
        }

        // $provider->password = Hash::make($request->password);
        // $provider->save();

        $token = $user->createToken('auth_token')->plainTextToken;

        if ($request->header('x-firebase-token')) {
            $user->firebase_token = $request->header('x-firebase-token');
            $user->save();
        }

        DB::table('password_reset_tokens')->where('email', $request->email)->delete();

        return $this->successResponse([
            'access_token' => $token,
            'token_type' => 'Bearer',
            'provider' => $user
        ], __('messages.reset_code_is_correct'));
    }

    /**
     * @OA\Post(
     *     path="/api/user/email/verify",
     *     summary="Verify user email",
     *     tags={"User Profile"},
     *      security={{"bearerAuth":{}}},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"token"},
     *             @OA\Property(property="token", type="string", example="1234")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Email verified successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="Email verified successfully.")
     *         )
     *     )
     * )
     */
    public function verifyEmail(Request $request)
    {

        $request->validate(
            ['token' => ['required', 'string']]
        )['token'];

        /** @var \App\Models\User $user */
        $user = Auth::user();

        $resetRecord = DB::table('password_reset_tokens')
            ->where('email', $user->email)
            ->first();

        if (!$resetRecord) {
            return $this->errorResponse(__('messages.invalid_token'), 400);
        }
        if (!Hash::check($request->token, $resetRecord->token)) {
            return $this->errorResponse(__('messages.invalid_token'), 400);
        }

        // if passes 10 minutes
        if (Carbon::now()->diffInMinutes($resetRecord->created_at) > 10) {
            return $this->errorResponse(__('messages.token_expired'), 400);
        }

        $user->email_verified_at = now();
        $user->save();
        DB::table('password_reset_tokens')->where('email', $user->email)->delete();

        return $this->successResponse(null, __('messages.email_verified'));
    }

    /**
     * @OA\Post(
     *     path="/api/user/email/send-verification",
     *     summary="Send email verification code",
     *     tags={"User Profile"},
     *     security={{"bearerAuth":{}}},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Verification code sent successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="A verification code has been sent to your email.")
     *         )
     *     )
     * )
     */
    public function sendEmailVerification()
    {
        /** @var \App\Models\User $user */
        $user = Auth::user();
        $token = strval(rand(1000, 9999));
        if (!app()->isProduction()) {
            $token = "0000";
        }
        DB::table('password_reset_tokens')->updateOrInsert(
            ['email' => $user->email],
            [
                'token' => Hash::make($token),
                'created_at' => Carbon::now()
            ]
        );
        $user->notify(new NewUserConfirmEmailNotification($user->name, $user->email, $token));

        return $this->successResponse(null, __('messages.code_sent_to_email'));
    }

    /**
     * @OA\Put(
     *     path="/api/user/password/change",
     *     summary="Change the authenticated user's password",
     *     tags={"User Authentication"},
     *     security={{"bearerAuth":{}}},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"password", "password_confirmation"},
     *             @OA\Property(property="password", type="string", format="password"),
     *             @OA\Property(property="password_confirmation", type="string", format="password")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Password changed successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object", nullable=true),
     *             @OA\Property(property="message", type="string", example="Password changed successfully.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=401,
     *         description="Unauthenticated"
     *     ),
     *     @OA\Response(
     *         response=422,
     *         description="Validation error"
     *     )
     * )
     */
    public function changePassword(Request $request)
    {
        $request->validate([
            'current_password' => 'sometimes',
            'password' => 'required|string|min:8|confirmed',
        ]);

        /** @var \App\Models\User $user */
        $user = Auth::user();

        if (isset($request->current_password) && !Hash::check($request->current_password, $user->password)) {
            return $this->errorResponse(__('messages.current_password_is_incorrect'), 422);
        }

        $user->password = Hash::make($request->password);
        $user->save();

        return $this->successResponse(null, __('messages.password_changed_successfully'));
    }
}
