<?php

declare(strict_types=1);

namespace Flowaxy\Domain\Plugin\Services;

use Exception;
use Flowaxy\Domain\Plugin\Services\ActivatePluginService;
use Flowaxy\Domain\Plugin\Services\DeactivatePluginService;
use Flowaxy\Domain\Plugin\Services\InstallPluginService;
use Flowaxy\Domain\Plugin\Services\PluginCacheInterface;
use Flowaxy\Domain\Plugin\Services\PluginFilesystemInterface;
use Flowaxy\Domain\Plugin\Services\PluginLifecycleInterface;
use Flowaxy\Domain\Plugin\Services\UninstallPluginService;
use Flowaxy\Support\Facades\Hooks;
use Flowaxy\Support\Facades\Log;
use Throwable;

// Сервіс управління життєвим циклом плагіна (Application Layer)
class ApplicationPluginLifecycleService implements PluginLifecycleInterface
{
    private ?string $lastInstallError = null;

    public function __construct(
        private readonly PluginFilesystemInterface $filesystem,
        private readonly PluginCacheInterface $cache,
        private readonly InstallPluginService $installer,
        private readonly ActivatePluginService $activator,
        private readonly DeactivatePluginService $deactivator,
        private readonly UninstallPluginService $uninstaller
    ) {
    }

    public function install(string $slug): bool
    {
        if ($slug === '' || !$this->filesystem->exists($slug)) {
            try {
                Log::Warning('Плагін не знайдено або невалідний slug', ['slug' => $slug]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return false;
        }

        $config = $this->filesystem->readConfig($slug);
        if ($config === null) {
            $exception = new Exception('Failed to read plugin config');
            try {
                Log::Error('Помилка читання конфігурації плагіна', ['exception' => $exception]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }

        // Перевіряємо, чи плагін потребує БД (має міграції)
        if ($this->filesystem->hasMigrations($slug)) {
            // Перевіряємо, чи підключена БД
            if (!$this->filesystem->isDatabaseConnected()) {
                try {
                    Log::Warning("Плагін {$slug} потребує базу даних, але БД не підключена. Встановлення заблоковано.", [
                        'slug' => $slug,
                    ]);
                } catch (Throwable $e) {
                    // Ignore logging errors
                }
                // Зберігаємо помилку для відображення користувачу
                $this->lastInstallError = 'Плагін потребує підключення до бази даних. Будь ласка, підключіть БД перед встановленням.';
                return false;
            }
        }

        // Установка плагіна без виконання міграцій (міграції виконуються при активації)
        $result = $this->installer->execute($slug, $config, function () {
            // Міграції не виконуються при установці - тільки при активації
        });

        if ($result) {
            $this->cache->afterInstall($slug);
            Hooks::dispatch('plugin_installed', $slug);
            $this->lastInstallError = null; // Очищаем ошибку при успешной установке
        } else {
            $exception = new Exception('Failed to install plugin');
            try {
                Log::Error('Помилка встановлення плагіна', ['exception' => $exception]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return $result;
    }

    /**
     * Отримати останню помилку встановлення плагіна
     *
     * @return string|null
     */
    public function getLastInstallError(): ?string
    {
        return $this->lastInstallError;
    }

    public function activate(string $slug): bool
    {
        if ($slug === '') {
            try {
                Log::Warning('Невалідний slug');
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return false;
        }

        // Виконуємо міграції перед активацією (згідно з ТЗ)
        $this->filesystem->runMigrations($slug);

        $result = $this->activator->execute($slug);
        if ($result) {
            $this->cache->afterActivate($slug);
            Hooks::dispatch('plugin_activated', $slug);
        } else {
            $exception = new Exception('Failed to activate plugin');
            try {
                Log::Error('Помилка активації плагіна', ['exception' => $exception]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return $result;
    }

    public function deactivate(string $slug): bool
    {
        if ($slug === '') {
            try {
                Log::Warning('Невалідний slug');
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return false;
        }

        $result = $this->deactivator->execute($slug);
        if ($result) {
            $this->cache->afterDeactivate($slug);
            Hooks::dispatch('plugin_deactivated', $slug);
        } else {
            $exception = new Exception('Failed to deactivate plugin');
            try {
                Log::Error('Помилка деактивації плагіна', ['exception' => $exception]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return $result;
    }

    public function uninstall(string $slug): bool
    {
        if ($slug === '') {
            try {
                Log::Warning('Невалідний slug');
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return false;
        }

        $result = $this->uninstaller->execute($slug, function () use ($slug) {
            $this->filesystem->delete($slug, '');
        });

        if ($result) {
            $this->cache->afterUninstall($slug);
            Hooks::dispatch('plugin_uninstalled', $slug);
        } else {
            $exception = new Exception('Failed to uninstall plugin');
            try {
                Log::Error('Помилка видалення плагіна', ['exception' => $exception]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return $result;
    }
}
