<?php


namespace Fliegerlogin;

// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Der Sniff haelt jede Interpolation fuer Ausgabe. Hier entsteht keine: die Werte gehen in Exception-Objekte, die intern gefangen und erst nach dem Maskieren angezeigt werden.


use Fliegerlogin\Error\ApiError;
use Fliegerlogin\Error\InvalidLoginCredentialsError;
use Fliegerlogin\Error\TwoFactorAuthenticationRequiredError;
use Fliegerlogin\VereinsfliegerApi\Api\AuthApi;
use Fliegerlogin\VereinsfliegerApi\Exceptions\ApiException;
use Fliegerlogin\VereinsfliegerApi\Exceptions\Exception;
use Fliegerlogin\VereinsfliegerApi\Exceptions\HttpException;
use Fliegerlogin\VereinsfliegerApi\Model\AccessTokenDto;
use Fliegerlogin\VereinsfliegerApi\Model\IUserDto;
use Fliegerlogin\VereinsfliegerApi\Model\SignInCredentialsDto;
use Fliegerlogin\VereinsfliegerApi\Model\VereinsfliegerResponseDto;
use Fliegerlogin\VereinsfliegerApi\Responses\LoginFailedResponse;

class Api {

	/** @var AuthApi */
	protected $auth;

	/** @var string */
	protected $accessToken = null;

	/** @var string */
	protected $cid = null;

	/** @var string */
	protected $appKey = null;

	function __construct() {
		$this->auth = new AuthApi();
	}

	/**
	 * @throws ApiError
	 */
	function init(): void {
		// get access token
		try {
			/** @var VereinsfliegerResponseDto & AccessTokenDto $result */
			$result = $this->auth->getAccesstoken();
			$this->auth->accesstoken = $result->getAccesstoken();
		} catch (\Exception $e) {
			throw new ApiError($e->getMessage(), $e->getCode(), $e);
		}
	}

	/**
	 * @param string      $username Username
	 * @param string      $password Password
	 * @param string|null $otp      One Time Password (only if 2FA is needed)
	 * @throws ApiError
	 * @throws InvalidLoginCredentialsError
	 * @throws TwoFactorAuthenticationRequiredError
	 */
	function login(string $username, string $password, ?string $otp = null): void {
		$credentials = new SignInCredentialsDto();

		$appKey = Options::getAppKey();
		if ($appKey !== null) {
			$credentials->setAppkey($appKey);
		}
		$cid = Options::getCID();
		if ($cid !== null) {
			$credentials->setCid($cid);
		}
		$credentials->setUsername($username);
		$credentials->setPassword($password);
		if ($otp) {
			$credentials->setAuthSecret($otp);
		}

		try {
			$this->auth->Signin($credentials);
		} catch (HttpException $e) {
			throw new ApiError($e->getMessage(), $e->getCode(), $e);
		} catch (ApiException $e) {
			if ($e->getSerializedBody() && is_a($e->getSerializedBody(), LoginFailedResponse::class)) {
				/** @var LoginFailedResponse $response */
				$response = $e->getSerializedBody();

				if ($response->getNeed2fa() == 1) {
					throw new TwoFactorAuthenticationRequiredError($response);
				} else {
					throw new InvalidLoginCredentialsError($response);
				}
			}
		}
	}

	/**
	 * @return true
	 * @throws ApiError
	 */
	function logout(): bool {
		try {
			$this->auth->Signout();
		} catch (HttpException $e) {
			throw new ApiError($e->getMessage(), $e->getCode(), $e);
		} catch (ApiException $e) {
			if ($e->getResponse()->getStatusCode() !== 401) {
				throw new ApiError($e->getMessage(), $e->getCode(), $e);
			}
		}

		return true;
	}

	/**
	 * @return IUserDto
	 * @throws ApiError
	 */
	function getUser(): IUserDto {
		try {
			return $this->auth->GetUser();
		} catch (Exception $e) {
			throw new ApiError($e->getMessage(), $e->getCode(), $e);
		}
	}

}