<?php
namespace Planaday;

use Planaday\Api\ApiConnector;
use Planaday\Database\Abstraction\DatabaseConnector;
use Planaday\Entities\DatabaseRefresher;
use Planaday\Platform\PlatformAbstraction\PlatformConnector;
use Planaday\Platform\PlatformAbstraction\PlatformService;
use Planaday\Utility\Debug\Log\Logging;
use Planaday\Utility\Debug\PluginFeatureTimer;
use Planaday\Utility\DependencyInjection\Container;
use Planaday\Utility\DependencyInjection\InjectionImpossibleException;
use Planaday\Utility\PluginData;

class Planaday
{
	use Logging;

	protected Container $registry;

	/**
	 * @param class-string<PlatformConnector> $platform
	 * @param class-string<DatabaseConnector> $database
	 * @param class-string<ApiConnector> $api
	 * @param string $fullPrefix
	 * @param string $shortPrefix
	 * @param string[] $version
	 * @param string $pluginFile
	 * @param Container|null $registryOverride
	 */
	public function __construct(
		string $platform,
		string $database,
		string $api,
		string $fullPrefix,
		string $shortPrefix,
		array $version,
		string $pluginFile,
		?Container $registryOverride = null
	) {
		if ($registryOverride !== null) $this->logInfo("Using provided registry");
		$this->registry = $registryOverride ?? new Container();
		$pluginData = new PluginData(
			$fullPrefix,
			$shortPrefix,
			$version,
			$pluginFile
		);
		$this->registry->setSingleton(PluginData::class, $pluginData);
		$this->registry->setSingleton(self::class, $this);
		$this->registry->doInjections($this);

		$this->logInfo("Connecting $fullPrefix with $platform, using database $database and API $api");
		if (is_a($platform, PlatformConnector::class, true)) {
			$this->registry->setImplementation(PlatformConnector::class, $platform);
		} else {
			$this->logWarning("Provided platform connector is not a valid platform connector");
		}

		if (is_a($database, DatabaseConnector::class, true)) {
			$this->registry->setImplementation(DatabaseConnector::class, $database);
		} else {
			$this->logWarning("Provided database connector is not a valid database connector");
		}

		if (is_a($api, ApiConnector::class, true)) {
			$this->registry->setImplementation(ApiConnector::class, $api);
		} else {
			$this->logWarning("Provided API connector is not a valid API connector");
		}
		$this->logInfo("Construction Done");
	}

	public function run(): void{
		try {
			$this->logInfo("Starting plugin, connecting to platform and API");
			$startupTimer = $this->registry->getInstance(PluginFeatureTimer::class)->start("Startup");

			$this->registry->getInstance(PlatformConnector::class)->connect();
			$this->registry->getInstance(DatabaseConnector::class)->connect();
			$this->registry->getInstance(ApiConnector::class)->connect();

			$this->logInfo("Creating PlatformService");

			$platformService = $this->registry->getInstance(PlatformService::class);

			$this->logInfo("Connected plugin, checking if API config is complete");

			$platformService->checkAndConnectTestApi();

			$this->logInfo("Checking if plugin is up to date");

			$platformService->updateCurrentVersion();

			$this->logInfo("Plugin up to date, refreshing database");

			$this->registry->getInstance(DatabaseRefresher::class)->refreshDatabases(false);

			$this->logInfo("Databases up to date, Running plugin");

			$platformService->run();
			$startupTimer();
		} catch ( InjectionImpossibleException $e ) {
			echo $e->getMessage();
		}
	}

	public function shutdown(): void {
		if(isset($this->registry)) $this->registry->destroy();
		unset($this->registry);
	}

	public function __destruct() {
		$this->shutdown();
	}
}