<?php
	
	namespace Main\Controllers;
	
	use Curl\Curl;
	use Main\Core\Auth;
	use Main\Core\Controller;
	use Main\Core\Redirect;
	use Main\Services\DiscordBotService;
	use PDO;
	
	class AccountLinkingController extends Controller
	{
		public function __construct()
		{
			if (!modules('account_linking')->isActive()) abort_404();
		}
		
		public function login($provider)
		{
			if (settings('loginProvider') != 'default') abort_404();
			
			$accountLinkingProvider = db()->prepare("SELECT * FROM AccountLinkingProviders WHERE slug = ? AND isEnabled = ?");
			$accountLinkingProvider->execute([$provider, 1]);
			$accountLinkingProvider = $accountLinkingProvider->fetch(PDO::FETCH_ASSOC);
			if (!$accountLinkingProvider) abort_404();
			
			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 == $accountLinkingProvider['slug']) {
					$validatedUserData = $oauthValidateTokenResponse->data;
					
					if (settings('gameType') == 'fivem' && $accountLinkingProvider['slug'] == 'steam') {
						$identifier = base_convert($validatedUserData->username, 10, 16);
					} else {
						$identifier = $validatedUserData->username;
					}
					
					$linkedAccount = db()->prepare("SELECT * FROM LinkedAccounts WHERE providerID = ? AND identifier = ?");
					$linkedAccount->execute([$accountLinkingProvider['id'], $identifier]);
					$linkedAccount = $linkedAccount->fetch(PDO::FETCH_ASSOC);
					if (!$linkedAccount) {
						$redirect = new Redirect(url('auth.login'));
						return $redirect->flash("error", t__('Your %provider% account is not linked to any account!', ['%provider%' => t__($accountLinkingProvider['name'])]));
					} else {
						return Auth::login($provider, $linkedAccount["accountID"], true);
					}
				} else {
					return $this->view('auth.failed', [
						'message' => t__('Something went wrong! Please try again later.')
					]);
				}
			} else {
				redirect('https://id.leaderos.net/redirect?provider=' . $accountLinkingProvider['slug'] . "&return=" . urlencode(website_url(url('account-linking.login', ['provider' => $provider]))) . "&s=" . LOCATION);
			}
		}
		
		public function link($provider)
		{
			$accountLinkingProvider = db()->prepare("SELECT * FROM AccountLinkingProviders WHERE slug = ? AND isEnabled = ? AND slug != ?");
			$accountLinkingProvider->execute([$provider, 1, settings('loginProvider')]);
			$accountLinkingProvider = $accountLinkingProvider->fetch(PDO::FETCH_ASSOC);
			if (!$accountLinkingProvider) abort_404();
			
			$linkedAccount = db()->prepare("SELECT * FROM LinkedAccounts WHERE accountID = ? AND providerID = ?");
			$linkedAccount->execute([auth()->user()->id(), $accountLinkingProvider['id']]);
			$linkedAccount = $linkedAccount->fetch(PDO::FETCH_ASSOC);
			if ($linkedAccount) abort_404();
			
			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 == $accountLinkingProvider['slug']) {
					$redirect = new Redirect(url("account.settings.linked-accounts"));
					$validatedUserData = $oauthValidateTokenResponse->data;
					
					if (settings('gameType') == 'fivem' && $accountLinkingProvider['slug'] == 'steam') {
						$identifier = base_convert($validatedUserData->username, 10, 16);
					} else {
						$identifier = $validatedUserData->username;
					}
					$displayName = $validatedUserData->realname;
					
					// Check if the linked account is already linked to another account
					$checkLinkedAccount = db()->prepare("SELECT * FROM LinkedAccounts WHERE providerID = ? AND identifier = ?");
					$checkLinkedAccount->execute([$accountLinkingProvider['id'], $identifier]);
					$checkLinkedAccount = $checkLinkedAccount->fetch(PDO::FETCH_ASSOC);
					if ($checkLinkedAccount) {
						return $redirect->flash("error", t__('Your %provider% account is already linked to another account!', ['%provider%' => t__($accountLinkingProvider['name'])]));
					}
					
					$insertConnection = db()->prepare("INSERT INTO LinkedAccounts (accountID, providerID, identifier, displayName, creationDate) VALUES (?, ?, ?, ?, ?)");
					$insertConnection->execute([
						auth()->user()->id(),
						$accountLinkingProvider['id'],
						$identifier,
						$displayName,
						datetime()
					]);
					
					if ($accountLinkingProvider['slug'] == 'discord' && DiscordBotService::isBotReady()) {
						// Send request to LeaderOS Discord Bot API to add discord roles
						$userRoles = db()->prepare("SELECT R.discordRoleID, AR.expiryDate FROM AccountRoles AR INNER JOIN Roles R ON AR.roleID = R.id WHERE AR.accountID = ? AND R.discordRoleID IS NOT NULL AND R.discordRoleID != '' AND (AR.expiryDate = '1000-01-01 00:00:00' OR AR.expiryDate > ?)");
						$userRoles->execute([auth()->user()->id(), datetime()]);
						$userRoles = array_map(function ($role) {
							return [
								'id' => $role['discordRoleID'],
								'expiryDate' => $role['expiryDate']
							];
						}, $userRoles->fetchAll(PDO::FETCH_ASSOC));
						
						$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) {
							$userRoles[] = [
								'id' => $defaultRole['discordRoleID'],
								'expiryDate' => '1000-01-01 00:00:00'
							];
						}
						
						DiscordBotService::linkUser($validatedUserData->username, auth()->user()->displayName(), $userRoles);
					}
					
					return $redirect->flash("success", t__('Your %provider% account has been successfully linked to your account!', ['%provider%' => t__($accountLinkingProvider['name'])]));
				} else {
					return $this->view('auth.failed', [
						'message' => t__('Something went wrong! Please try again later.')
					]);
				}
			} else {
				redirect('https://id.leaderos.net/redirect?provider=' . $accountLinkingProvider['slug'] . "&return=" . urlencode(website_url(url('account-linking.link'))) . "&s=" . LOCATION);
			}
		}
		
		public function unlink($provider)
		{
			$accountLinkingProvider = db()->prepare("SELECT * FROM AccountLinkingProviders WHERE slug = ? AND isEnabled = ? AND slug != ?");
			$accountLinkingProvider->execute([$provider, 1, settings('loginProvider')]);
			$accountLinkingProvider = $accountLinkingProvider->fetch(PDO::FETCH_ASSOC);
			if (!$accountLinkingProvider) abort_404();
			
			$linkedAccount = db()->prepare("SELECT * FROM LinkedAccounts WHERE accountID = ? AND providerID = ?");
			$linkedAccount->execute([auth()->user()->id(), $accountLinkingProvider['id']]);
			$linkedAccount = $linkedAccount->fetch(PDO::FETCH_ASSOC);
			if (!$linkedAccount) abort_404();
			
			if ($accountLinkingProvider['slug'] == 'discord' && DiscordBotService::isBotReady()) {
				// Send request to LeaderOS Discord Bot API to remove discord roles
				$siteRoles = db()->query("SELECT discordRoleID FROM Roles WHERE discordRoleID IS NOT NULL AND discordRoleID != ''");
				$siteRoles = $siteRoles->fetchAll(PDO::FETCH_ASSOC);

				DiscordBotService::unlinkUser($linkedAccount['identifier'], array_column($siteRoles, 'discordRoleID'));
			}
			
			$unlinkAccount = db()->prepare("DELETE FROM LinkedAccounts WHERE accountID = ? AND providerID = ?");
			$unlinkAccount->execute([auth()->user()->id(), $accountLinkingProvider['id']]);
			
			$redirect = new Redirect(url("account.settings.linked-accounts"));
			return $redirect->flash("success", t__('Your %provider% account has been successfully unlinked from your account!', ['%provider%' => t__($accountLinkingProvider['name'])]));
		}
	}