<?php

namespace App\Services;

use Illuminate\Http\Request;
use App\Libs\Consts\StatusConst;
use App\Repositories\Interfaces\EmailVerificationRepositoryInterface;
use App\Repositories\Interfaces\PasswordResetRepositoryInterface;
use App\Repositories\Interfaces\UserRepositoryInterface;
use Carbon\Carbon;
use DateTime;
use Illuminate\Auth\AuthManager;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Session;
use Stevebauman\Location\Facades\Location;

class AuthenticateService
{

    protected $auth;
    protected $userRepository;
    protected $passwordResetRepository;
    protected $emailService;
    protected $emailVerificationRepository;

    /**
     * Create AuthenticateService Instance.
     *
     * @param $userRepository
     *
     * @return void
     */
    public function __construct(
        AuthManager $auth,
        UserRepositoryInterface $userRepository,
        PasswordResetRepositoryInterface $passwordResetRepository,
        EmailService $emailService,
        EmailVerificationRepositoryInterface $emailVerificationRepository
    ) {
        $this->auth = $auth;
        $this->userRepository = $userRepository;
        $this->passwordResetRepository = $passwordResetRepository;
        $this->emailService = $emailService;
        $this->emailVerificationRepository = $emailVerificationRepository;
    }

    public function authenticate($request)
    {
        $response = [];
        $response['redirect'] = '';
        $response['status']  =  '';
        $response['message']  =  '';

        $credentials = $request->only('email', 'password');
        $credentials['status'] = StatusConst::ACTIVE;
        $credentials['app_id'] = config('desxpert.app_id');

        $rememberMe =  $request->has('remember_me') ? true : false;

        if ($this->auth->attempt($credentials, $rememberMe)) {

            $response['redirect'] = '/dashboard';

            return $response;
        }
        $response['redirect'] = '/login';
        $response['status'] = 'errorMessage';
        $response['message'] = 'Invalid Credentials. ';
        return $response;
    }

    function get_ip()
    {
        $keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');

        foreach ($keys as $key) {
            if (array_key_exists($key, $_SERVER) === true) {
                foreach (explode(',', $_SERVER[$key]) as $ip) {
                    if (filter_var($ip, FILTER_VALIDATE_IP) !== false) {
                        return $ip;
                    }
                }
            }
        }
    }
    public function changePassword($request)
    {
        $response = [];

        $verificationCode = $this->emailVerificationRepository->getByColumn('verification_code', $request->verification);

        $isValid = $this->checkIfCodeIsValid($verificationCode->expire_at);

        if ($isValid) {
            $this->setNewPassword($request->password, $verificationCode->user_id);

            $this->emailVerificationRepository->removeCode($request->verification);

            Auth::loginUsingId($verificationCode->user_id);

            $response['redirect'] = '/dashboard';
            $response['status'] = '';
            $response['message'] = '';
        } else {
            $response['redirect'] = config('app.url') . '/set-password?link=' . $verificationCode->verification_code;
            $response['status'] = '';
            $response['message'] = '';
        }

        return $response;
    }

    public function forgotPassword($request)
    {
        $user = $this->userRepository->getByColumn('email', $request->email);

        if (!$user) {
            $response['redirect'] = '/forgot-password';
            $response['status'] = 'errorMessage';
            $response['message'] = "Email doesn't exist!";

            return $response;
        }

        $codeDateCreated = Carbon::now();
        $generatedCode = Hash::make($user->email);

        $emailPayload = [
            'user_id' => $user->id,
            'verification_code' => $generatedCode,
            'expire_at' => $codeDateCreated->addMinutes(30),
        ];
        $existingLink = $this->emailVerificationRepository->getByColumn('user_id', $user->id);
        if ($existingLink) {
            $this->emailVerificationRepository->removeCode($existingLink->verification_code);
        }
        $this->emailService->storeVerificationCode($emailPayload);

        $emailInfo = [
            'name' => $user->name,
            'email' => $user->email,
            'link' => config('app.url') . '/set-password?link=' . $generatedCode,
        ];


        $this->emailService->sendEmail('forgot-password', $emailInfo);

        $response['redirect'] = '/login';
        $response['status'] = 'successMessage';
        $response['message'] = 'A message has been sent to you by email with the instructions on how to reset your password.';

        return $response;
    }

    public function setPassword($request)
    {
        $link = $request->get('link');
        $response['view'] = 'errors.index';
        $response['title'] = 'OOPS. . . . LINK IS NO LONGER AVAILABLE! ';
        $response['body'] = 'Your forgot password link seems expired or invalid.';

        if (empty($link)) {
            $response['view'] = 'auth.login';
            $response['title'] = '';
            $response['body'] = '';
            return $response;
        }

        // verify the link if expired or existing
        $verificationCode = $this->emailVerificationRepository->getByColumn('verification_code', $link);

        if (empty($verificationCode)) {
            return $response;
        } else {

            $isValid = $this->checkIfCodeIsValid($verificationCode->expire_at);

            if ($isValid) {
                $response['view'] = 'auth.set-password';
                $response['title'] = '';
                $response['body'] = $verificationCode->verification_code;
            }
        }

        return $response;
    }

    public function logout()
    {
        Auth::logout();
        Session::flush();

        return;
    }

    public function randomString($length)
    {
        $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
        $password = array();
        $alphaLength = strlen($alphabet) - 1;
        for ($i = 0; $i < $length; $i++) {
            $n = rand(0, $alphaLength);
            $password[] = $alphabet[$n];
        }
        return implode($password);
    }

    public function checkIfCodeIsValid($expiryDate)
    {
        $expirationDate = new DateTime($expiryDate);
        $interval = Carbon::now()->diff($expirationDate);

        return $interval->format('%a') > 3 ? false : true;
    }

    public function setNewPassword($password, $userId)
    {
        $payload = [];
        $payload['password'] = Hash::make($password);
        $payload['verified'] = StatusConst::VERIFIED;
        $payload['status'] = StatusConst::ACTIVE;

        $this->userRepository->update($payload, $userId);
    }
}
