<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;

use App\Models\OTP;
use App\Models\User;

use App\Http\Requests\LoginRequest;
use App\Http\Requests\RegisterRequest;

class AuthController extends Controller
{
    /**
     * @var bool
     */
    private bool $api_call;
    /**
     * @brief assign true|false to $api_call by checking if the request is an API call
     *
     * @return void
     */
    public function __construct() {
        $this->api_call = request()->header('Accept') == "application/json";
    }
    /**
     * @param $mobile
     * @param $otpval
     *
     * @return void
     */
//    private function sendOTP($mobile, $otpval) {
//    }

    /**
     * @param $mobile
     *
     * @return OTP
     */
    public function createOTP($mobile) {
        $otpval = generateRandomString(6, 'numeric');
        $otp = new OTP();
        $otp->otp = $otpval;
        $otp->mobile = $mobile;
        $otp->expire_at = date('Y-m-d H:i:s', time()+180);
        $otp->save();
        return $otp;
    }
    /**
     * @param $mobile
     * @param $otpval
     *
     * @return mixed
     */
    public function validateOTP($mobile, $otpval) {
        $current_datetime = date('Y-m-d H:i:s', time());
        return OTP::where('otp', $otpval)->where('mobile', $mobile)->where('expire_at','>',$current_datetime)->exists();
    }

    /**
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Foundation\Application
     */
    public function viewLogin() {
        return view('v1/01_public/login');
    }
    /**
     * @param LoginRequest $request
     *
     * @brief This method authenticates a user with their username and password. When a user is successfully authenticated,
     * the `Auth` facade `attempt()` method returns the JWT token. The generated token is retrieved and returned as JSON with the user object
     *
     * @return \Illuminate\Http\RedirectResponse|string
     * @throws ValidationException
     */
    public function login(LoginRequest $request) {
        /**
         * user can either use `mobile` or `email` as `username`
         */
        $username_index = filter_var(request('username'), FILTER_VALIDATE_EMAIL) ? 'email' : 'mobile';
        $credentials = [
            $username_index => request('username'),
            'password' => request('password')
        ];
        /**
         * attempt to authenticate and log in the user based on provided credentials
         */
        if (!$this->api_call) {
            if (auth()->attempt($credentials)) {
                session()->regenerate();
                auth()->user();
                return redirect()->route('dashboard.view');
            }
            /**
             *
             */
            throw ValidationException::withMessages(['err'=>'نام کاربری یا رمز عبور صحیح نیست']);
        } else {
            /**
             * validating user credentials, if validated, JWT will be generated
             * otherwise, `throwUnauthorizedError` will return a 401 response
             */
            $token = auth()->guard('api')->attempt($credentials);
            if (!$token)
                throwUnauthorizedError(['errors' => ['نام کاربری/رمز عبور نامعتبر']]);
            /**
             * credentials are valid and user is authenticated successfully
             * if user is an admin, they can't log in using the API (based on the contract)
             */
            $user = auth()->guard('api')->user();
            if ($user->role == 10) {
                auth()->guard('api')->logout();
                throwForbiddenError(['errors' => ['Admin is forbidden log in via the API']]);
                exit();
            }
            /**
             * response contains a JWT as authorisation bearer and some necessary user information
             */
            return successfulResponse([
                'authorisation' => [
                    'token' => $token,
                    'type' => 'bearer',
                ],
                'userinfo' => [
                    'id' => $user->id,
                    'firstname' => $user->firstname,
                    'lastname' => $user->lastname,
                ]
            ]);
        }

    }

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function viewRegister() {
        return view('v1/01_public/register-user');
    }

    /**
     * @param RegisterRequest $request
     *
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|void
     */
    public function register(RegisterRequest $request) {
        if (request('type') == 'otprequest') {
            $result = $this->createOTP(request('mobile'));
            return response()->json($result, 200);
        } elseif (request('type') == 'register') {
            if ($this->validateOTP(request('mobile'), request('otpval'))) {
                /**
                 * generating a unique affiliate code for the user
                 */
                $aff_code  = generateRandomString(10, 'string');
                $check_aff = User::where('aff_code', $aff_code)->count();
                while ($check_aff > 0) {
                    $aff_code  = generateRandomString(10, 'string');
                    $check_aff = User::where('aff_code', $aff_code)->count();
                }
                /**
                 * creating and saving new user
                 */
                $user = new User;
                $user->firstname = request('firstname');
                $user->lastname  = request('lastname');
                $user->mobile    = request('mobile');
                $user->idnum     = request('idnum');
                $user->email     = request('email');
                $user->password  = request('password');
                $user->aff_code  = $aff_code;
                $user->save();
                if (!$this->api_call) {
                    /**
                     * set proper sessions to redirect to /dashboard
                     */
                    session()->regenerate();
                    auth()->login($user);
                    return redirect('/panel/dashboard');
                } else {
                    /**
                     * authenticating the new user
                     * response contains a JWT as authorisation bearer and some necessary user information
                     */
                    $token = auth()->guard('api')->login($user);
                    return successfulResponse([
                        'authorisation' => [
                            'token' => $token,
                            'type' => 'bearer',
                        ],
                        'userinfo' => [
                            'id' => $user->id,
                            'firstname' => $user->firstname,
                            'lastname' => $user->lastname,
                        ]
                    ]);
                }
            } else {
                if (!$this->api_call)
                    return redirect()->route('register.view')->with( 'error', 'کد اعتبارسنجی نامعتبر' );
                else
                    throwUnauthorizedError(['errors' => ['Invalid OTP']]);

            }
        } else
            !$this->api_call ? abort(400) : throwBadRequestError();
    }

    public function forgetPassword() {

    }
    /**
     * `refresh`:
     * This method invalidates the user `Auth` token and generates a new token
     *
     * @return string
     */
    public function refresh() {
        if (auth()->guard('api')->check())
            return successfulResponse([
                'authorisation' => [
                    'token' => auth()->guard('api')->refresh(),
                    'type' => 'bearer',
                ],
                'userinfo' => [
                    'id' => auth()->guard('api')->user()->id,
                    'firstname' => auth()->guard('api')->user()->firstname,
                    'lastname' => auth()->guard('api')->user()->lastname,
                ]
            ]);
        else
            throwUnauthorizedError(['errors' => ['Token Expired, please log in again']]);
    }
    /**
     * `logout`:
     * This method invalidates the user `Auth` token
     *
     * @return \Illuminate\Http\RedirectResponse|string
     */
    public function logout() {
        auth()->logout();
        return !$this->api_call ? redirect()->route('home') : successfulResponse();
    }
}
