<?php

namespace Main\Controllers\Auth;

use Curl\Curl;
use Main\Core\Auth;
use Main\Core\Controller;
use Main\Services\DiscordBotService;
use Main\Services\PasswordService;
use Main\Services\SeoService;
use Main\Services\AccountLinkingService;
use Main\Services\UserService;
use PDO;

class LoginController extends Controller
{
		protected string $route_type = 'login';
		
		public function __construct()
		{
			if (auth()->check()) {
				redirect(url('account.profile.index'));
			}
		}
		
    public function index()
    {
	      SeoService::set('auth.login');
				
				if (get('redirect')) {
					session()->set('redirect', get('redirect'));
				} else {
					session()->remove('redirect');
				}
				
				$loginProvider = settings('loginProvider');
				if ($loginProvider != 'default') {
					if (isset($_GET["auth_token"])) {
						$oauthToken = get('auth_token');
						$oauthValidateTokenRequest = new Curl();
						$oauthValidateTokenRequest->setHeader('X-Api-Key', settings('apiKey'));
						$oauthValidateTokenRequest->post("https://id.leaderos.net/api/tokens/$oauthToken/validate");
						if ($oauthValidateTokenRequest->error) {
							if (settings('debugModeStatus') == 1) {
								var_dump($oauthValidateTokenRequest->error);
								exit;
							}
							return $this->view('auth.failed', [
								'message' => t__('Something went wrong! Please try again later.')
							]);
						}
						$oauthValidateTokenResponse = $oauthValidateTokenRequest->response;
						if (!isset($oauthValidateTokenResponse->status) || !isset($oauthValidateTokenResponse->data)) {
							if (settings('debugModeStatus') == 1) {
								var_dump($oauthValidateTokenResponse);
								exit;
							}
							return $this->view('auth.failed', [
								'message' => t__('Something went wrong! Please try again later.')
							]);
						}
						if ($oauthValidateTokenResponse->status && $oauthValidateTokenResponse->data->provider == $loginProvider) {
							$validatedUserData = $oauthValidateTokenResponse->data;
							
							if (settings('gameType') == 'fivem' && $loginProvider == 'steam') {
								$username = base_convert($validatedUserData->username, 10, 16);
							} else {
								$username = $validatedUserData->username;
							}
							
							$account = db()->prepare("SELECT * FROM Accounts WHERE username = ?");
							$account->execute(array($username));
							$account = $account->fetch();
							if (!$account) {
								if (settings("maintenanceStatus") == 1) {
									return view('auth.failed', [
										'message' => t__('The site is under maintenance!')
									]);
								}
								
								$loginToken = rand_token();
								
								$uuid = null;
								$realname = $validatedUserData->realname;
								$email = $validatedUserData->email;
								$avatar = $validatedUserData->avatar;
								$password = null;
								
								if ($email != null) {
									$emailValid = db()->prepare("SELECT COUNT(id) FROM Accounts WHERE email = ? LIMIT 1");
									$emailValid->execute(array($email));
									$emailCount = $emailValid->fetchColumn();
									if ($emailCount > 0) {
										return $this->view('auth.failed', [
											'message' => t__('<strong>%email%</strong> already registered!', ['%email%' => $email])
										]);
									}
								}
								
								if (settings("registerLimit") != "-1") {
									$ipCount = db()->prepare("SELECT COUNT(id) FROM Accounts WHERE creationIP = ?");
									$ipCount->execute(array(getIP()));
									$ipCount = $ipCount->fetchColumn();
									
									if ($ipCount >= (int)settings("registerLimit")) {
										return $this->view('auth.failed', [
											'message' => t__('You have reached the limit of registrations!')
										]);
									}
								}
								
								$insertAccounts = db()->prepare("INSERT INTO Accounts (uuid, username, realname, email, password, isVerified, creationIP, creationDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
								$insertAccounts->execute(array($uuid, $username, $realname, $email, $password, (modules("email_verification")->isActive() ? "0" : "1"), getIP(), datetime()));
								$accountID = db()->lastInsertId();
								$insertAccountSessions = db()->prepare("INSERT INTO AccountSessions (accountID, loginToken, useragent, creationIP, expiryDate, creationDate) VALUES (?, ?, ?, ?, ?, ?)");
								$insertAccountSessions->execute(array($accountID, $loginToken, $_SERVER['HTTP_USER_AGENT'], getIP(), createDuration(365), datetime()));
								session()->set('login', $loginToken);
								cookies()->set('rememberMe', $loginToken, 365 * 60 * 60 * 24);
								
								if ($avatar != null) {
									UserService::uploadAvatarFromUrl($accountID, $avatar);
								}
								
								if (DiscordBotService::isBotReady()) {
									$defaultRole = db()->prepare('SELECT discordRoleID FROM Roles WHERE slug = ? AND discordRoleID IS NOT NULL AND discordRoleID != "" LIMIT 1');
									$defaultRole->execute(['default']);
									$defaultRole = $defaultRole->fetch(PDO::FETCH_ASSOC);
									if ($defaultRole) {
										DiscordBotService::linkUser($validatedUserData->username, $validatedUserData->realname, [
											[
												'id' => $defaultRole['discordRoleID'],
												'expiryDate' => '1000-01-01 00:00:00'
											]
										]);
									}
								}
								
								redirect(url('account.profile.index'));
							} else {
								// If custom avatars are disabled, update the avatar
								// We want to update the avatar every login, because users can't change their avatars, we want to keep them up-to-date
								if (settings('allowCustomAvatars') == 0 && $validatedUserData->avatar != null) {
									UserService::uploadAvatarFromUrl($account["id"], $validatedUserData->avatar);
								}
								
								// If display name is different, update it
								if ($account["realname"] != $validatedUserData->realname) {
									$updateRealname = db()->prepare("UPDATE Accounts SET realname = ? WHERE id = ?");
									$updateRealname->execute(array($validatedUserData->realname, $account["id"]));
								}
								
								return Auth::login($loginProvider, $account["id"], true);
							}
						} else {
							return $this->view('auth.failed', [
								'message' => t__('Something went wrong! Please try again later.')
							]);
						}
					} else {
						redirect('https://id.leaderos.net/redirect?provider=' . $loginProvider . "&return=" . urlencode(website_url(url('auth.login'))) . "&s=" . LOCATION);
					}
				}
	    
		    $providers = AccountLinkingService::getProviders();

        return $this->view('auth.login', compact('providers'));
    }

    public function login()
    {
		    // Don't allow login if the login provider is not default
		    if (settings('loginProvider') != 'default') abort_404();
	    
	      validate([
            'username' => 'required',
            'password' => 'required',
            'rememberMe' => 'nullable|accepted'
        ]);
	    
		    if (recaptcha()->isEnabled('login') && !recaptcha()->verify()) {
			    return back()->flash('error', t__('Spam detected!'));
		    }
				
				$username = sanitize(input("username"));
	    
		    $account = db()->prepare("SELECT * FROM Accounts WHERE username = ?");
		    $account->execute(array($username));
		    $account = $account->fetch();
		    if (!$account) {
			    return back()->flash('error', t__('<strong>%username%</strong> not found!', ['%username%' => $username]));
		    }
		    
		    $password = PasswordService::match(input("password"), $account["password"]);
		    if (!$password) {
			    return back()->flash('error', t__('Wrong password!'));
		    }
				
				Auth::login('default', $account["id"], input("rememberMe"));
    }
}