<?php

namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
use App\Libs\Facades\Localization;
use App\Mail\NewUserLogin;
use BackendRole;
use BackendUser;
use Google_Client;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\ValidationException;
use ReCaptcha\ReCaptcha;
use Throwable;

class LoginController extends Controller
{

    use AuthenticatesUsers;

    protected $redirectTo = '/admin';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest:admin')->except('logout');
    }

    /**
     * Show the application's login form.
     *
     * @return \Illuminate\View\View
     */
    public function showLoginForm()
    {
        $website = get_website_from_url();
        if (is_null($website)) {
            abort(404);
        }
        return view('admin.pages.auth.login')->with([
            'website' => $website,
            'googleClientId' => config('services.google.client_id')
        ]);
    }

    /**
     * Show the application's login form.
     *
     * @return \Illuminate\View\View
     */
    public function showPasswordLoginForm()
    {
        $website = get_website_from_url();
        if (is_null($website)) {
            abort(404);
        }
        return view('admin.pages.auth.password-login')->with([
            'website' => $website
        ]);
    }

    /**
     * Handle a login request to the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function login(Request $request)
    {
        $website = get_website_from_url();
        if (is_null($website)) {
            abort(404);
        }

        $this->validateLogin($request);

        $bu = BackendUser::where('username', $request->input('username'))
            ->first();
        if ($bu && explode('@', $bu->email)[1] == 'southpole.com') {
            return redirect()->route('admin.login');
        }

        if ($this->attemptLogin($request)) {
            $user = $this->guard()->user();

            $websites = $user->websites;
            $website = $websites->find($website->id);

            if(empty($website)){
                $this->guard()->logout();

                $request->session()->invalidate();

                $request->session()->regenerateToken();

                throw ValidationException::withMessages([
                    'error' => ['This website is not set for the current user'],
                ]);
            }

            return $this->sendLoginResponse($request);
        }

        return $this->sendFailedLoginResponse($request);
    }

    /**
     * Validate the user login request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return void
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    protected function validateLogin(Request $request)
    {
        $request->validate([
            $this->username() => 'required|string',
            'password' => 'required|string',
            'g-recaptcha-response' => 'required'
        ]);

        $secret = config('google.recaptcha.secretKey');
        $remoteIp = request()->getClientIp();
        $recaptcha = new ReCaptcha($secret);
        $resp = $recaptcha->verify($request->input('g-recaptcha-response'), $remoteIp);
        if (!$resp->isSuccess()) {
            throw ValidationException::withMessages([
                'error' => ['Invalid Recaptcha'],
            ]);
        }
    }

    /**
     * Get the login username to be used by the controller.
     *
     * @return string
     */
    public function username()
    {
        return 'username';
    }

    /**
     * The user has logged out of the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return mixed
     */
    protected function loggedOut(Request $request)
    {
        return redirect()->route('admin.login');
    }

    /**
     * Get the guard to be used during authentication.
     *
     * @return \Illuminate\Contracts\Auth\StatefulGuard
     */
    protected function guard()
    {
        return Auth::guard('admin');
    }

    /**
     * Validate the "ID Token" using the Google API Client Library.
     * https://developers.google.com/identity/gsi/web/guides/verify-google-id-token
     */
    public function googleLogin(Request $request)
    {
        if ($_COOKIE['g_csrf_token'] !== $request->input('g_csrf_token')) {
            // Invalid CSRF token
            throw ValidationException::withMessages([
                'error' => ['Invalid CSRF. Please try again or contact tech support'],
            ]);
        }

        $idToken = $request->input('credential');

        $client = new Google_Client([
            'client_id' => config('services.google.client_id')
        ]);

        $payload = $client->verifyIdToken($idToken);

        if (!$payload) {
            // Invalid ID token
            throw ValidationException::withMessages([
                'error' => ['Invalid token. Please try again or contact tech support'],
            ]);
        }

        $user = BackendUser::where('email', $payload['email'])->first();

        if (!$user) {
            if ($payload['email_verified'] && !empty($payload['hd']) && $payload['hd'] == 'southpole.com') {
                $username = explode('@', $payload['email'])[0];

                // finds unique username
                $testUsername = $username;
                $i = 1;
                while (BackendUser::where('username', $testUsername)->count()) {
                    $testUsername = $username . '_' . $i;
                }

                $userData = [
                    'name' => $payload['name'],
                    'username' => $testUsername,
                    'email' => $payload['email'],
                    'backend_role_id' => BackendRole::where('short_name', 'read')->first()->id,
                    'password' => random_string('md5')
                ];

                DB::beginTransaction();
                try {
                    $user = BackendUser::create($userData);
                    // TODO: find a better away to associate website with signup
                    $user->websites()->sync([1 => ['is_default' => 1]]);
                    DB::commit();
                } catch (Throwable $e) {
                    DB::rollback();
                    Log::error($e);
                    throw ValidationException::withMessages([
                        'error' => ['Error registering new user'],
                    ]);
                }

                Mail::to(config('mail.addresses.backoffice.email'), config('mail.addresses.backoffice.name'))
                    ->send(new NewUserLogin($user, $user->websites->first()));
            } else {
                throw ValidationException::withMessages([
                    'error' => ['User access not permitted, please contact website administrators for more information'],
                ]);
            }
        }

        $this->guard()->login($user);

        return $this->sendLoginResponse($request);
    }
}
