<?php

namespace StevenBuehner\sbChurchtoolsGrouphomepage\Always;

use StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\GuzzleHttp\Cookie\CookieJar;
use StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\GuzzleHttp\Exception\ServerException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\Pimple\Container;
use StevenBuehner\ChurchTools\Api\CalendarApi;
use StevenBuehner\ChurchTools\Api\CampusApi;
use StevenBuehner\ChurchTools\Api\GroupApi;
use StevenBuehner\ChurchTools\Api\PersonApi;
use StevenBuehner\ChurchTools\Configuration;
use StevenBuehner\ChurchToolsApi\ChurchToolsClientInterface;
use StevenBuehner\ChurchToolsApi\ChurchToolsUserAuthenticatedClient;
use StevenBuehner\sbChurchtoolsGrouphomepage\Backend\BackendController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Backend\MailerSettingsController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\AppointmentListController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\CountdownFrontendController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\EventMetaDataFrontendController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\GlobalRestController as GlobalRestControllerAlias;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\GroupHomepageFrontendController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\NewsletterFrontendController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\NewsletterSettingsController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\PersonsFrontendController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Helper\CacheHelper;
use StevenBuehner\sbChurchtoolsGrouphomepage\Helper\iCalHelper;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\CtCalendarService;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\CtCampusService;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\CtGroupService;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\CtNewsletterService;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\CtPersonService;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\Exceptions\LoginException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\Mail\SmtpMailer;

class MyContainer extends Container {
	protected static $myself;

	public function __construct() {
		parent::__construct([]);
		$this->registerStuff();
	}

	protected function registerStuff(): void {

		$this['debugMode'] = function ($c) {
			// return false;
			$siteUrl = get_site_url();
			return preg_match('~(\.test|localhost:?[0-9]*)$~', get_site_url()) === 1;
		};

		$this['domain'] = function ($c) {
			return $c['pluginData']['TextDomain'];
		};


		/**
		 * i.e. sbWissensportal/sbWissensportal.php
		 */
		$this['pluginId'] = function ($c) {

			$regex = '~^(' . str_replace('/', '\/', preg_quote(WP_CONTENT_DIR)) . ')\/([^\/]+)\/([^\/]+)\/.*~';
			$d     = preg_replace($regex, '$3/$3.php', __FILE__);

			return $d;

		};

		/**
		 * i.e. /home/vagrant/web/wp-content/plugins/sbWissensportal/sbWissensportal.php
		 */
		$this['pluginIdAbsolutePath'] = function ($c) {
			$regex = '~^(' . str_replace('/', '\/', preg_quote(WP_CONTENT_DIR)) . ')\/([^\/]+)\/([^\/]+)\/.*~';
			$d     = preg_replace($regex, '$1/$2/$3/$3.php', __FILE__);

			return $d;

		};

		$this['pluginData'] = function ($c) {
			if (!function_exists('get_plugin_data')) {
				require_once(ABSPATH . 'wp-admin/includes/plugin.php');
			}
			return get_plugin_data($c['pluginIdAbsolutePath'], TRUE, FALSE);
		};

		$this['version'] = function ($c) {
			return $c['pluginData']['Version'];
		};


		$this['activator'] = function ($c) {
			return new Activator($this['pluginId'], $this['domain']);
		};

		$this['deactivator'] = function ($c) {
			return new Deactivator();
		};

		$this['mailer'] = function ($c) {

			$mailConfig = [
				'host'     => MailerSettingsController::getHost(),
				'username' => MailerSettingsController::getUsername(),
				'password' => MailerSettingsController::getPassword(),
				'secure'   => MailerSettingsController::getSecure(),
				'timeout'  => MailerSettingsController::getTimeout(),
			];

			return new SmtpMailer($mailConfig);
		};

		$this['backendController'] = function ($c) {
			return new BackendController($this['domain'], $c['version']);
		};

		$this['globalRestController'] = function ($c) {
			return new GlobalRestControllerAlias($this['domain'], $c['version'], $c['debugMode']);
		};

		$this['appointmentListController'] = function ($c) {
			return new AppointmentListController($this['domain'], $c['version'], $c['debugMode']);
		};

		$this['groupHomepageController'] = function ($c) {
			return new GroupHomepageFrontendController($this['domain'], $c['version'], $c['debugMode']);
		};

		$this['eventMetaDataController'] = function ($c) {
			return new EventMetaDataFrontendController($this['domain'], $c['version'], $c['debugMode']);
		};

		$this['personsController'] = function ($c) {
			return new PersonsFrontendController($this['domain'], $c['version'], $c['debugMode']);
		};

		$this['mainController'] = function ($c) {
			return new MainController($this['domain']);
		};

		$this['mailerSettingsController'] = function ($c) {
			return new MailerSettingsController($c['domain']);
		};

		$this['countdownController'] = function ($c) {
			return new CountdownFrontendController($c['domain'], $c['version'], $c['debugMode']);
		};

		$this['newsletterController'] = function ($c) {
			return new NewsletterFrontendController($c['domain'], $c['version'], $c['debugMode'], $c['CtNewsletterService']);
		};

		$this['newsletterSettingsController'] = function ($c) {
			return new NewsletterSettingsController($c['domain']);
		};

		$this['CtNewsletterConfig'] = function ($c) {
			/** @var NewsletterSettingsController $newsletterSettingsController */
			$newsletterSettingsController = $c['newsletterSettingsController'];

			$config = Configuration::getDefaultConfiguration();
			$config->setHost($newsletterSettingsController->getApiUrl());
			$config->setUsername($newsletterSettingsController->getUsername());
			$config->setPassword($newsletterSettingsController->getPassword());

			return $config;
		};

		$this['CtNewsletterClient'] = function ($c) {
			$cookieJar          = new CookieJar();
			$guzzleClientParams = [
				'connect_timeout' => 7 // 7 sekunden
			];
			$debugClient        = TRUE;

			// Client-Debugging braucht die composer-dev packages
			if ($debugClient === FALSE) {
				$logger = new \Monolog\Logger('Guzzle-Client-Logger');
				$logger->pushHandler(new \Monolog\Handler\StreamHandler(__DIR__ . '/../debug_guzzle.log'), \StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\Psr\Log\LogLevel::DEBUG);

				// https://github.com/gmponos/guzzle-log-middleware
				$stack = \StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\GuzzleHttp\HandlerStack::create();
				$stack->push(new \GuzzleLogMiddleware\LogMiddleware($logger));
				$guzzleClientParams['handler'] = $stack;
			}

			return new ChurchToolsUserAuthenticatedClient($c['CtNewsletterConfig'], $cookieJar, $guzzleClientParams);
		};

		$this['CtNewsletterOpenSslKey'] = function ($c) {

			$optionValue = get_option('ct_newsletter_openssl_key', NULL);
			$response    = NULL;

			if ($optionValue !== NULL) {
				try {
					$response = unserialize($optionValue);
				} catch (\Exception $e) {
					$response = NULL;
				}
			}

			if ($response === NULL || $response === FALSE) {
				$config = [
					"digest_alg"       => 'sha256',
					"private_key_bits" => 2048,
					"private_key_type" => OPENSSL_KEYTYPE_RSA
				];

				// New Key (Ressource)
				$opensslKeyResource = openssl_pkey_new($config);

				// Export Public Key (String)
				$publicKey = openssl_pkey_get_details($opensslKeyResource)['key'];

				// Export Private Key (String)
				openssl_pkey_export($opensslKeyResource, $privateKey);

				// Store Keys
				$response = [
					'public'  => $publicKey,
					'private' => $privateKey,
					'config'  => $config

				];

				add_option('ct_newsletter_openssl_key', serialize($response));

			}

			return $response;

		};

		$this['CtNewsletterService'] = function ($c) {
			return new CtNewsletterService($c['CtNewsletterClient'], $c['CtNewsletterConfig'], $c['CtNewsletterOpenSslKey']);
		};

		$this['CtGroupService'] = function ($c) {
			return new CtGroupService($c['churchToolsGroupApi']);
		};

		$this['CtPersonService'] = function ($c) {
			return new CtPersonService($c['churchToolsPersonApi']);
		};

		$this['CtCalendarService'] = function ($c) {
			return new CtCalendarService();
		};

		$this['CtCampusService'] = function ($c) {
			return new CtCampusService();
		};

		$this['churchToolsCalendarApi'] = function ($c): CalendarApi {
			return new CalendarApi($c['CtNewsletterClient'], $c['CtNewsletterConfig']);
		};

		$this['churchToolsCampusApi'] = function ($c): CampusApi {
			return new CampusApi($c['CtNewsletterClient'], $c['CtNewsletterConfig']);
		};

		$this['churchToolsGroupApi'] = function ($c): GroupApi {
			return new GroupApi($c['CtNewsletterClient'], $c['CtNewsletterConfig']);
		};

		$this['churchToolsPersonApi'] = function ($c): PersonApi {
			return new PersonApi($c['CtNewsletterClient'], $c['CtNewsletterConfig']);
		};

		$this['pdo_connection'] = function ($c) {

			list($link, $user, $password) = $c['db_config'];

			return new \PDO($link, $user, $password);
		};

		$this['db_config'] = function ($c) {
			if (!defined('DB_NAME')) {
				require_once dirname(dirname(dirname(dirname(__DIR__)))) . '/wp-config.php';
			}

			global $table_prefix;

			// $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
			return [
				'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=' . DB_CHARSET,
				DB_USER,
				DB_PASSWORD,
				$table_prefix
			];
		};

		$this['table_prefix'] = function ($c) {
			list($link, $user, $password, $prefix) = $c['db_config'];

			return $prefix;
		};

		$this['l10n'] = function ($c) {

			// Load db-config if not done yet
			$c['db_config'];

			global $l10n;

			return $l10n;

		};


	}

	/**
	 * @return BackendController
	 */
	public static function getBackendController(): BackendController {
		$container = self::getSingleton();

		return $container['backendController'];
	}

	/**
	 * @return MyContainer
	 */
	public static function getSingleton(): MyContainer {
		if (!self::$myself) {
			self::$myself = new MyContainer();
		}

		return self::$myself;
	}

	/**
	 * @return
	 */
	public static function getGlobalRestController(): mixed {
		$container = self::getSingleton();

		return $container['globalRestController'];
	}

	/**
	 * @return AppointmentListController
	 */
	public static function getAppointmentListController(): AppointmentListController {
		$container = self::getSingleton();

		return $container['appointmentListController'];
	}

	/**
	 * @return GroupHomepageFrontendController
	 */
	public static function getGrouphomepageController(): GroupHomepageFrontendController {
		$container = self::getSingleton();

		return $container['groupHomepageController'];
	}

	/**
	 * @return EventMetaDataFrontendController
	 */
	public static function getEventMetaDataController(): EventMetaDataFrontendController {
		$container = self::getSingleton();

		return $container['eventMetaDataController'];
	}

	/**
	 * @return NewsletterFrontendController
	 */
	public static function getNewsletterController(): NewsletterFrontendController {
		$container = self::getSingleton();

		return $container['newsletterController'];
	}

	/**
	 * @return CountdownFrontendController
	 */
	public static function getCountdownController(): CountdownFrontendController {
		$container = self::getSingleton();

		return $container['countdownController'];
	}


	/**
	 * @return PersonsFrontendController
	 */
	public static function getPersonsController(): PersonsFrontendController {
		$container = self::getSingleton();

		return $container['personsController'];
	}

	/**
	 * @return CalendarApi
	 */
	public static function getCalendarApi(): CalendarApi {
		$container = self::getSingleton();

		return $container['churchToolsCalendarApi'];
	}


	/**
	 * @return CtGroupService
	 */
	public static function getCtGroupService(): CtGroupService {
		$container = self::getSingleton();

		return $container['CtGroupService'];
	}

	/**
	 * @return CtPersonService
	 */
	public static function getCtPersonService(): CtPersonService {
		$container = self::getSingleton();

		return $container['CtPersonService'];
	}


	/**
	 * @return CampusApi
	 */
	public static function getCampusApi(): CampusApi {
		$container = self::getSingleton();

		return $container['churchToolsCampusApi'];
	}

	/**
	 * @return ChurchToolsClientInterface
	 */
	public static function churchToolsLogin(): ChurchToolsClientInterface {
		$container = self::getSingleton();

		/** @var ChurchToolsClientInterface $client */
		$client = $container['CtNewsletterClient'];
		try {
			$client->login();
		} catch (ServerException $e) {
			throw new LoginException('Fataler Fehler beim ChurchTools login');
		}

		return $client;

	}

	/**
	 * @return Configuration
	 */
	public static function getChurchToolsConfig(): Configuration {
		$container = self::getSingleton();

		/** @var Configuration $client */
		return $container['CtNewsletterConfig'];
	}

	/**
	 * @param $url
	 * @return mixed|iCalHelper|string
	 * @throws \StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\Psr\Cache\InvalidArgumentException
	 */
	public static function getIcalHelper($url) {
		$container = self::getSingleton();
		$key       = sha1('iCalHelper/' . $url);

		if (!isset($container->keys()[$key])) {
			$container[$key] = new iCalHelper($url);
		}

		return $container[$key];

	}

	/**
	 * @return \StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\Symfony\Component\Cache\Adapter\FilesystemAdapter
	 */
	public static function getCacheAdapter() {
		return CacheHelper::getInstance();
	}

	/**
	 * @return CtCalendarService
	 */
	public static function getCtCalendarService(): CtCalendarService {

		$container = self::getSingleton();

		/** @var CtCalendarService */
		return $container['CtCalendarService'];
	}


	/**
	 * @return CtCampusService
	 */
	public static function getCtCampusService(): CtCampusService {

		$container = self::getSingleton();

		/** @var CtCampusService */
		return $container['CtCampusService'];
	}

	/**
	 * @return SmtpMailer
	 */
	public static function getMailer(): SmtpMailer {

		$container = self::getSingleton();

		/** @var SmtpMailer */
		return $container['mailer'];
	}

	public static function isDebugMode(): bool {

		$container = self::getSingleton();

		return $container['debugMode'];

	}

}
