<?php


namespace App\Repositories;


use App\Models\Event;
use App\Models\User;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Crypt;
use App\Jobs\SendForgotPasswordLinkMail;
use App\Jobs\SendResetPasswordSuccessMail;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Carbon;

class AuthRepository
{
    use AuthenticatesUsers;

    /**
     * @param Request $request
     * @param null $role
     * @return JsonResponse
     */
    public function authenticate(Request $request, $role = null): JsonResponse
    {
        $input = $request->all();
        // validate login request
        $validator = Validator::make($input, [
            'email' => 'required|string|email',
            'password' => 'required|string',
        ]);

        if ($validator->fails()) {
            return response()->json(["success" => false, "errors" => $validator->errors()], 200);
        } else {
            /**
             * Lock user for 1 minute if failed attempts in login
             */
            if ($this->hasTooManyLoginAttempts($request)) {
                $this->fireLockoutEvent($request);
                return response()->json(["success" => false, "errors" => ["password" => ["Too many failed attempts! Please try after 1 minute"]]], 200);
            }

            // getting remember flag
            $remember = $input["remember"];

            $eventSlug = $input["event_slug"];
            $event = Event::whereSlugName($eventSlug)->first();

            unset($input["remember"]);
            unset($input["event_slug"]);

            if (Auth::attempt($input, $remember)) {
                $user = Auth::user();
                if ($role) {
                    $userRoleCheck = false;
                    if ($role === 'super_admin')
                        $userRoleCheck = $user->hasRole($role);
                    elseif ($event) {
                        $eventUser = getEventUser($event, $user);
                        $userRoleCheck = $eventUser && $eventUser->hasRole($role);
                    } else {
                        $userWithRole = $user->hasEventRole($role);
                        if (count($userWithRole) > 0)
                            $userRoleCheck = true;
                    }
                    if (!$userRoleCheck) {
                        Auth::logout();
                        return response()->json(["errors" => ["email" => ["Not a valid user"]], "status" => false], 200);
                    }
                }
                if ($user->valid) {
                    $user->events = $user->getEventWithRoles()->get();
                    activity('user.login')
                        ->causedBy($user)
                        ->log('User logged in');
                    return response()->json(
                        [
                            "message" => "success",
                            "status" => true,
                            "user" => $user,
                            "have_abstracts" => 0,
                            "role" => $role
                        ],
                        200
                    );
                } else {
                    return response()->json(["errors" => ["email" => ["Not a valid user"]], "status" => false], 200);
                }
            } else if (!User::whereEmail($input["email"])->first()) {
                $this->incrementLoginAttempts($request);
                return response()->json(["status" => false, "errors" => ["email" => ["The email address was not found. Please double check and try again"]]], 200);
            } else {
                $this->incrementLoginAttempts($request);
                return response()->json(["status" => false, "errors" => ["password" => ["Invalid credentials"]]], 200);
            }
        }
    }

    public function authenticateWithGuard($email, $password)
    {

        return Auth::guard('web')->attempt([
            'email' => $email,
            'password' => $password
        ]);
    }

    public function logout(Request $request)
    {
        $causer = who($request);
        Auth::logout();
        activity('user.logout')
            ->causedBy($causer->user)
            ->log('User logged out');
        return response([
            'status' => true,
            'message' => 'Successfully logged out'
        ]);
    }


    /**
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function generateForgotPasswordLink(Request $request)
    {
        $email = $request->input('email');
        $user = User::whereEmail($email)->first();

        if (!$user) {
            return response([
                'status' => false,
                'message' => 'User does not exists'
            ]);
        } else {

            $token['id'] = $user->id;
            $token = Crypt::encrypt($token);

            $tokenValue['token'] = $token;
            $tokenValue['email'] = $user->email;
            $tokenValue['expTime'] = date('Y-m-d H:i:s', time());

            $tokenData = json_encode($tokenValue);

            //saving tokendata in to user table
            $user->forgot_password = $tokenData;
            $user->save();

            //sending mail to user
            dispatch(new SendForgotPasswordLinkMail($user, $token));

            return response([
                'status' => true,
                'message' => 'Forgot password link send successfully'
            ]);
        }
    }

    /**
     * Check the password reset token is valid
     *
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function checkForgotPasswordToken(Request $request)
    {
        $token = $request->input('token');

        $user = User::where('forgot_password->token', '=', $token)->first();

        if (!$user) {
            return response([
                'status' => false,
                'message' => 'Invalid Token'
            ]);
        } else {

            $tokenValue = json_decode($user->forgot_password);

            if ($tokenValue->expTime <= Carbon::now()->subHours(1)) {
                return response([
                    'status' => false,
                    'message' => 'Token Expired'
                ]);
            } else if ($user->email == $tokenValue->email) {
                return response([
                    'status' => true,
                    'message' => 'Token Is Valid'
                ]);
            } else {
                return response([
                    'status' => false,
                    'message' => 'Invalid Token'
                ]);
            }
        }
    }

    /**
     * Resets password of a user
     *
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function resetPassword(Request $request)
    {
        $input = $request->all();
        // validate reset password request
        $validator = Validator::make($input, [
            'password' => 'required|string|min:8|confirmed',
        ]);

        if ($validator->fails()) {
            return response([
                "status" => false,
                "errors" => $validator->errors()
            ]);
        } else {
            $user = User::where('forgot_password->token', '=', $input['token'])->first();

            $tokenValue = json_decode($user->forgot_password);

            if (!$user) {
                return response([
                    'status' => false,
                    'message' => 'Invalid user'
                ]);
            } else if ($tokenValue->expTime <= Carbon::now()->subHours(1)) {
                return response([
                    'status' => false,
                    'message' => 'token expired'
                ]);
            } else {
                $user->password = Hash::make($input['password']);
                $user->forgot_password = null; // invalidating the token
                $user->save();

                //send reset success email to user
                dispatch(new SendResetPasswordSuccessMail($user));

                return response([
                    'status' => true,
                    'message' => "Password reset successfully"
                ]);
            }
        }
    }
}
