<?php

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Persistence\Repositories;

use Flowaxy\Core\System\PathResolver;
use Flowaxy\Domain\Plugin\Entities\Plugin;
use Flowaxy\Domain\Plugin\Services\PluginRepositoryInterface;
use Flowaxy\Infrastructure\Config\PluginConfigManager;
use Flowaxy\Infrastructure\Config\PluginSettingsManager;
use Flowaxy\Support\Facades\Log;
use Throwable;

use function array_filter;
use function basename;
use function glob;
use const DS;
use const GLOB_ONLYDIR;

final class PluginRepository implements PluginRepositoryInterface
{
    private string $pluginsDir;

    public function __construct()
    {
        $this->pluginsDir = PathResolver::plugins() . DS;
    }

    /**
     * @return array<int, Plugin>
     */
    public function all(): array
    {
        $plugins = [];
        $directories = glob($this->pluginsDir . '*', GLOB_ONLYDIR) ?: [];

        foreach ($directories as $dir) {
            $slug = basename($dir);
            $plugins[] = $this->mapPlugin($slug);
        }

        return array_filter($plugins);
    }

    public function find(string $slug): ?Plugin
    {
        return $this->mapPlugin($slug);
    }

    public function install(Plugin $plugin): bool
    {
        try {
            // Устанавливаем статус плагина как 'deactive' (установлен, но не активирован)
            $result = PluginConfigManager::setStatus($plugin->slug, 'deactive');

            // Создаем файл настроек плагина при установке (даже пустой)
            if ($result) {
                try {
                    $ds = defined('DS') ? DS : DIRECTORY_SEPARATOR;
                    $pluginsConfigDir = PathResolver::storageConfig() . $ds . 'plugins';
                    $settingsPath = $pluginsConfigDir . $ds . $plugin->slug . '.ini';

                    // Создаем директорию, если её нет
                    if (!is_dir($pluginsConfigDir)) {
                        @mkdir($pluginsConfigDir, 0755, true);
                    }

                    // Создаем файл настроек, если его нет
                    if (!file_exists($settingsPath)) {
                        // Пробуем через PluginSettingsManager
                        $saveResult = PluginSettingsManager::saveSettings($plugin->slug, []);

                        // Если не получилось, создаем файл напрямую
                        if (!$saveResult || !file_exists($settingsPath)) {
                            $content = "[settings]\n";
                            $directResult = @file_put_contents($settingsPath, $content) !== false;

                            if ($directResult && file_exists($settingsPath)) {
                                @chmod($settingsPath, 0644);
                                try {
                                    Log::Debug('PluginRepository::install: Plugin settings file created directly', [
                                        'slug' => $plugin->slug,
                                        'path' => $settingsPath,
                                    ]);
                                } catch (Throwable $logError) {
                                    // Ignore logging errors
                                }
                            } else {
                                try {
                                    Log::Warning('PluginRepository::install: Failed to create plugin settings file', [
                                        'slug' => $plugin->slug,
                                        'path' => $settingsPath,
                                        'dir_exists' => is_dir($pluginsConfigDir),
                                        'dir_writable' => is_dir($pluginsConfigDir) ? is_writable($pluginsConfigDir) : false,
                                    ]);
                                } catch (Throwable $logError) {
                                    // Ignore logging errors
                                }
                            }
                        } else {
                            try {
                                Log::Debug('PluginRepository::install: Plugin settings file created successfully', [
                                    'slug' => $plugin->slug,
                                    'path' => $settingsPath,
                                ]);
                            } catch (Throwable $logError) {
                                // Ignore logging errors
                            }
                        }
                    }
                } catch (Throwable $settingsError) {
                    // Логируем ошибку, но не прерываем установку
                    try {
                        Log::Error('PluginRepository::install: Error creating plugin settings file', [
                            'slug' => $plugin->slug,
                            'error' => $settingsError->getMessage(),
                            'exception' => $settingsError,
                        ]);
                    } catch (Throwable $logError) {
                        // Ignore logging errors
                    }
                }
            }

            return $result;
        } catch (Throwable $e) {
            try {
                Log::Error('PluginRepository::install: Failed to install plugin', [
                    'slug' => $plugin->slug,
                    'error' => $e->getMessage(),
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    public function uninstall(string $slug): bool
    {
        try {
            try {
                Log::Debug('PluginRepository::uninstall: Starting uninstallation', [
                    'slug' => $slug,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }

            // Удаляем плагин из конфигурации
            $result = PluginConfigManager::remove($slug);

            try {
                Log::Debug('PluginRepository::uninstall: PluginConfigManager::remove() result', [
                    'slug' => $slug,
                    'result' => $result,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }

            // Удаляем настройки плагина
            $settingsDeleted = PluginSettingsManager::deleteSettings($slug);

            try {
                Log::Debug('PluginRepository::uninstall: PluginSettingsManager::deleteSettings() result', [
                    'slug' => $slug,
                    'result' => $settingsDeleted,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }

            try {
                Log::Info('PluginRepository::uninstall: Plugin uninstalled successfully', [
                    'slug' => $slug,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }

            return $result;
        } catch (Throwable $e) {
            try {
                Log::Error('PluginRepository::uninstall: Failed to uninstall plugin', [
                    'slug' => $slug,
                    'error' => $e->getMessage(),
                    'exception' => $e,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    public function activate(string $slug): bool
    {
        try {
            try {
                Log::Debug('PluginRepository::activate: Starting activation', [
                    'slug' => $slug,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }

            $result = PluginConfigManager::setStatus($slug, 'active');

            try {
                Log::Debug('PluginRepository::activate: PluginConfigManager::setStatus() result', [
                    'slug' => $slug,
                    'result' => $result,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }

            return $result;
        } catch (Throwable $e) {
            try {
                Log::Error('PluginRepository::activate: Failed to activate plugin', [
                    'slug' => $slug,
                    'error' => $e->getMessage(),
                    'exception' => $e,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    public function deactivate(string $slug): bool
    {
        try {
            return PluginConfigManager::setStatus($slug, 'deactive');
        } catch (Throwable $e) {
            try {
                Log::Error('PluginRepository::deactivate: Failed to deactivate plugin', [
                    'slug' => $slug,
                    'error' => $e->getMessage(),
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    /**
     * @return array<string, mixed>
     */
    public function getSettings(string $slug): array
    {
        try {
            return PluginSettingsManager::getSettings($slug);
        } catch (Throwable $e) {
            try {
                Log::Error('PluginRepository::getSettings: Failed to get plugin settings', [
                    'slug' => $slug,
                    'error' => $e->getMessage(),
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return [];
        }
    }

    public function setSetting(string $slug, string $key, mixed $value): bool
    {
        try {
            return PluginSettingsManager::setValue($slug, $key, $value);
        } catch (Throwable $e) {
            try {
                Log::Error('PluginRepository::setSetting: Failed to set plugin setting', [
                    'slug' => $slug,
                    'key' => $key,
                    'error' => $e->getMessage(),
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    private function updateActiveState(string $slug, bool $active): bool
    {
        if ($this->connection === null) {
            return false;
        }

        try {
            $stmt = $this->connection->prepare('UPDATE plugins SET is_active = ? WHERE slug = ?');

            return $stmt->execute([$active ? 1 : 0, $slug]);
        } catch (\PDOException $e) {
            try {
                Log::Error('Помилка оновлення стану плагіна', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    private function mapPlugin(string $slug): ?Plugin
    {
        $config = $this->readConfig($slug);

        if ($config === null) {
            return null;
        }

        $merged = array_merge(
            [
                'slug' => $slug,
                'name' => ucfirst($slug),
                'version' => '1.0.0',
                'description' => '',
                'author' => '',
            ],
            $config
        );

        // Получаем статус из конфигурации
        $status = PluginConfigManager::getStatus($slug);
        $isActive = $status === 'active';

        return new Plugin(
            slug: $merged['slug'],
            name: $merged['name'],
            version: $merged['version'],
            active: $isActive,
            description: $merged['description'] ?? '',
            author: $merged['author'] ?? '',
            meta: $merged
        );
    }

    /**
     * @return array<string, mixed>|null
     */
    private function readConfig(string $slug): ?array
    {
        try {
            // Используем PluginMetadataHelper для чтения метаданных из Plugin.php
            $config = \Flowaxy\Support\Helpers\PluginMetadataHelper::readMetadata($slug);
            return !empty($config) ? $config : null;
        } catch (\Throwable $e) {
            try {
                Log::Error("Помилка читання конфігурації плагіна ({$slug})", ['exception' => $e, 'slug' => $slug]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return null;
        }
    }

}
