<?php

namespace HassanKerdash\Modular\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use HassanKerdash\Modular\Support\FinderCollection;
use HassanKerdash\Modular\Support\ModuleRegistry;
use HassanKerdash\Modular\Support\PhpStorm\LaravelConfigWriter;
use HassanKerdash\Modular\Support\PhpStorm\PhpFrameworkWriter;
use HassanKerdash\Modular\Support\PhpStorm\ProjectImlWriter;
use HassanKerdash\Modular\Support\PhpStorm\WorkspaceWriter;
use Symfony\Component\Finder\SplFileInfo;

class ModulesSync extends Command
{
	protected $signature = 'modules:sync {--no-phpstorm : Do not update PhpStorm config files}';

	protected $description = 'Sync your project\'s configuration with your current modules';

	/**
	 * @var \Illuminate\Filesystem\Filesystem
	 */
	protected $filesystem;

	/**
	 * @var \HassanKerdash\Modular\Support\ModuleRegistry
	 */
	protected $registry;

	public function handle(ModuleRegistry $registry, Filesystem $filesystem)
	{
		$this->filesystem = $filesystem;
		$this->registry = $registry;

		$this->updatePhpUnit();

		$registry->reload();

		if (true !== $this->option('no-phpstorm'))
			$this->updatePhpStormConfig();
	}

	protected function updatePhpUnit(): void
	{
		$config_path = $this->getLaravel()->basePath('phpunit.xml');

		if (! $this->filesystem->exists($config_path)) {
			$this->warn('No phpunit.xml file found. Skipping PHPUnit configuration.');
			return;
		}

		$modules_directory = config('app-modules.modules_directory', 'app-modules');

		$config = simplexml_load_string($this->filesystem->get($config_path));

		$existing_nodes = $config->xpath("//phpunit//testsuites//testsuite//directory[text()='./{$modules_directory}/*/tests']");

		if (count($existing_nodes)) {
			$this->info('Modules test suite already exists in phpunit.xml');
			return;
		}

		$testsuites = $config->xpath('//phpunit//testsuites');
		if (! count($testsuites)) {
			$this->error('Cannot find <testsuites> node in phpunit.xml file. Skipping PHPUnit configuration.');
			return;
		}

		$testsuite = $testsuites[0]->addChild('testsuite');
		$testsuite->addAttribute('name', 'Modules');

		$directory = $testsuite->addChild('directory');
		$directory->addAttribute('suffix', 'Test.php');
		$directory[0] = "./{$modules_directory}/*/tests";

		$config->formatOutput = true;

		$this->filesystem->put($config_path, $config->asXML());
		$this->info('Added "Modules" PHPUnit test suite.');
	}

	protected function updatePhpStormConfig(): void
	{
		$this->updatePhpStormLaravelPlugin();
		$this->updatePhpStormPhpConfig();
		$this->updatePhpStormWorkspaceConfig();
		$this->updatePhpStormProjectIml();
	}

	protected function updatePhpStormLaravelPlugin(): void
	{
		$config_path = $this->getLaravel()->basePath('.idea/laravel-plugin.xml');
		$writer = new LaravelConfigWriter($config_path, $this->registry);

		if ($writer->handle()) {
			$this->info('Updated PhpStorm/Laravel Plugin config file...');
		} else {
			$this->info('Did not find/update PhpStorm/Laravel Plugin config.');
			if ($this->getOutput()->isVerbose()) {
				$this->warn($writer->last_error);
			}
		}
	}

	protected function updatePhpStormPhpConfig(): void
	{
		$config_path = $this->getLaravel()->basePath('.idea/php.xml');
		$writer = new PhpFrameworkWriter($config_path, $this->registry);

		if ($writer->handle()) {
			$this->info('Updated PhpStorm PHP config file...');
		} else {
			$this->info('Did not find/update PhpStorm PHP config.');
			if ($this->getOutput()->isVerbose()) {
				$this->warn($writer->last_error);
			}
		}
	}

	protected function updatePhpStormWorkspaceConfig(): void
	{
		$config_path = $this->getLaravel()->basePath('.idea/workspace.xml');
		$writer = new WorkspaceWriter($config_path, $this->registry);

		if ($writer->handle()) {
			$this->info('Updated PhpStorm workspace library roots...');
		} else {
			$this->info('Did not find/update PhpStorm workspace config.');
			if ($this->getOutput()->isVerbose()) {
				$this->warn($writer->last_error);
			}
		}
	}

	protected function updatePhpStormProjectIml(): void
	{
		$idea_directory = $this->getLaravel()->basePath('.idea/');
		if (! $this->filesystem->isDirectory($idea_directory)) {
			return;
		}

		FinderCollection::forFiles()
			->in($idea_directory)
			->name('*.iml')
			->first(function(SplFileInfo $file) {
				$config_path = $file->getPathname();
				$writer = new ProjectImlWriter($config_path, $this->registry);

				if ($writer->handle()) {
					$this->info("Updated PhpStorm project source folders in '{$file->getBasename()}'");
					return true;
				}

				$this->info("Could not update PhpStorm project source folders in '{$file->getBasename()}'");

				if ($this->getOutput()->isVerbose()) {
					$this->warn($writer->last_error);
				}

				return false;
			});
	}
}
