<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\ErrorLog;
use App\Models\Settings;
use App\Models\UserOauth;
use Exception;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;

class OauthController extends Controller
{
    public string|null|object $service;

    public function __construct()
    {
        $this->service = request()->route('service');

        $services = ['github', 'discord', 'google'];
        if (!in_array($this->service, $services)) {
            redirect()->back()->send();
        }
        $this->setConfig();
    }

    public function connect()
    {
        try {
            return Socialite::driver($this->service)->redirect();
        } catch (Exception $error) {
            ErrorLog::catch('oauth::connect::' . $this->service, $error->getMessage());
            return redirect()->route('user.settings')->with('error',
                    trans('auth.oauth_failed',
                        ['default' => "Authentication Failed: Please contact an Administrator, errors have been logged."])
                );
        }
    }

    public function remove()
    {
        if (Auth::user()->oauthService($this->service)->exists()) {
            Auth::user()->oauthService($this->service)->first()->delete();
        }

        return redirect()->route('user.settings')->with('success',
                trans('auth.oauth_disconnect',
                    ['service' => $this->service, 'default' => ":service was disconnected from your account."])
            );
    }

    public function callback()
    {
        try {
            $user = Socialite::driver($this->service)->user();

            // ensure whether the driver/email combination is unique
            if (UserOauth::query()->where(['driver' => $this->service, 'email' => $user->getEmail()])->exists()) {
                return redirect()->route('user.settings')->with('error',
                        trans('auth.oauth_connect_exist_error',
                            ['service' => $this->service, 'default' => ":service is already connected to your account."])
                    );
            }
            
            // store the user for the service
            $this->{$this->service}($user);
        } catch (Exception $error) {
            ErrorLog::catch('oauth::callback::' . $this->service, $error->getMessage());
            return redirect()->route('user.settings')->with('error',
                    trans('auth.oauth_connect_error',
                        ['default' => "Something went wrong, please try again."])
                );
        }

        return redirect()->route('user.settings')->with('success',
        trans('auth.oauth_connect_success',
            ['service' => $this->service, 'default' => "Successfully connected :service to your account."])
        );
    }

    // store the user for Google
    protected function google($user)
    {
        // ensure user is verified on Google
        if (!$user->user['verified_email']) {
            return redirect()->route('user.settings')->with('error',
                    trans('auth.oauth_google_verified_error',
                        ['default' => "Your Google account is not verified."])
                );
        }

        UserOauth::query()->UpdateOrCreate([
            'user_id' => Auth::user()->id,
            'driver' => $this->service,
            'email' => $user->getEmail(),
            'data' => $user->user,
        ]);
    }

    // store the user for GitHub
    protected function github($user)
    {
        UserOauth::query()->UpdateOrCreate([
            'user_id' => Auth::user()->id,
            'driver' => $this->service,
            'email' => $user->getEmail(),
            'external_profile' => $user->user['html_url'],
            'data' => $user->user,
        ]);
    }

    // store the user for GitHub
    protected function discord($user)
    {
        // ensure user is verified on discord
        if (!$user->user['verified']) {
            return redirect()->route('user.settings')->with('error',
                    trans('auth.oauth_discord_verified_error',
                        ['default' => 'Your Discord account is not verified.'])
                );
        }

        UserOauth::query()->UpdateOrCreate([
            'user_id' => Auth::user()->id,
            'driver' => $this->service,
            'email' => $user->getEmail(),
            'data' => $user->user,
        ]);
    }

    /**
     * This function dynamically sets the values for config/services.php
     * so that oauth services can retrieve settings set by the user in the admin area
     *
     * @return void
     */
    protected function setConfig(): void
    {
        config([
            'services.' . $this->service . '.client_id' => Settings::getJson('encrypted::oauth::' . $this->service, 'client_id')
        ]);

        config([
            'services.' . $this->service . '.client_secret' => Settings::getJson('encrypted::oauth::' . $this->service, 'client_secret')
        ]);

        config([
            'services.' . $this->service . '.redirect' => config('app.url') . '/oauth/' . $this->service . '/redirect'
        ]);
    }

}
