<?php

namespace App\Http\Controllers\Auth;

use Carbon\Carbon;
use Illuminate\Contracts\View\View;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Laravel\Socialite\Facades\Socialite;

use App\Http\Controllers\Controller;
use App\Mail\SocialLink;
use App\Models\{ProviderOauth,ProviderToken,User,UserOauth};

class SocialLoginController extends Controller
{
	public function redirectToProvider($provider)
	{
		return Socialite::with($provider)
			->redirect();
	}

	public function handleProviderCallback($provider)
	{
		$openiduser = Socialite::with($provider)->user();

		if (! $openiduser)
			return redirect('home')
				->with('error','No user details obtained.');

		$oo = ProviderOauth::firstOrCreate(['name'=>$provider,'active'=>TRUE]);

		// See if this user has connected and linked previously
		$aoo = $oo->users->where('userid',$openiduser->id);

		if ($aoo->count() === 1) {
			$aoo = $aoo->first();

			if ((is_null($user=$aoo->user) && (is_null($aoo->account) || is_null($user=$aoo->account->user))) || ! $user->active) {
				if (! $user)
					$user = User::where('email',$openiduser->email)->first();

				if ((! $user) || (! $user->active))
					return redirect('login')
						->with('error','Invalid account, or account inactive, please contact an admin.');

				return $this->link($provider,$aoo,$user);
			}

			// All Set to login
			Auth::login($user);

		// If there are too many users, then we have a problem
		} elseif ($aoo->count() > 1) {
			return redirect('login')
				->with('error','Seems you have multiple oauth IDs, please contact an admin.');

		// User is using OAUTH for the first time.
		} else {
			$uo = User::active()->where('email',$openiduser->email);

			// See if their is an account with this email address
			if ($uo->count() === 1) {
				$aoo = new UserOauth;
				$aoo->userid = $openiduser->id;
				$aoo->oauth_data = $openiduser->user;

				$oo->users()->save($aoo);

				return $this->link($provider,$aoo,$uo->first());

			// If there are too many users, then we have a problem
			} elseif ($uo->count() > 1) {
				return redirect('login')
					->with('error','Seems you have multiple accounts, please contact an admin.');

			} else {
				return redirect('login')
					->with('error','Seems you dont have an account with that email, please contact an admin.');
			}
		}

		return redirect()
			->intended('/home');
	}

	public function handleBearerTokenCallback($provider)
	{
		$openiduser = Socialite::with($provider)->user();

		if (! $openiduser)
			return redirect('home')
				->with('error','No user details obtained.');

		$po = ProviderOauth::where('name',$provider)->singleOrFail();

		$uoo = ProviderToken::where('user_id',Auth::id())->where('provider_oauth_id',$po->id)->firstOrNew();

		$uoo->user_id = Auth::id();
		$uoo->access_token = $openiduser->token;
		$uoo->access_token_expires_at = Carbon::now()->addSeconds($openiduser->expiresIn);
		$uoo->refresh_token = $openiduser->refreshToken;
		$uoo->refresh_token_expires_at = Carbon::now()->addSeconds($openiduser->refresh_token_expires_in);
		$uoo->realm_id = $openiduser->realmid;

		$po->tokens()->save($uoo);

		return redirect()
			->intended('/home')
			->with('success','Token refreshed.');
	}

	/**
	 * We have identified the user and oauth, just need them to confirm the link
	 *
	 * @param $provider
	 * @param UserOauth $ao
	 * @param User $uo
	 * @return View
	 */
	public function link($provider,UserOauth $ao,User $uo): View
	{
		// @note If this is sent now (send()), it results in the caller to be executed a second time (handleProviderCallback()).
		Mail::to($uo->email)->queue(new SocialLink($ao));

		return view('theme.backend.adminlte.auth.social_link')
			->with('oauthid',$ao->id)
			->with('provider',$provider);
	}

	public function linkcomplete(Request $request,$provider)
	{
		// Load our oauth id
		$aoo = UserOauth::findOrFail($request->post('oauthid'));

		// Check our email matches
		if (Arr::get($aoo->oauth_data,'email','invalid') !== $request->post('email'))
			return redirect('login')
				->with('error','Account details didnt match to make link.');

		// Check our token matches
		if ($aoo->link_token !== $request->post('token'))
			return redirect('login')
				->with('error','Token details didnt match to make link.');

		// Load our email.
		$uo = User::where('email',$request->post('email'))->firstOrFail();

		// Incase we have an existing record with a different oauthid
		UserOauth::where('user_id',$uo->id)->delete();

		$aoo->user_id = $uo->id;
		$aoo->save();
		Auth::login($uo);

		return redirect()
			->intended('/home');
	}
}