<?php

declare(strict_types=1);

namespace Inpsyde\MultilingualPress\Module\LanguageManager;

use Inpsyde\Assets\Asset;
use Inpsyde\Assets\AssetManager;
use Inpsyde\Assets\Script;
use Inpsyde\Assets\Style;
use Inpsyde\MultilingualPress\Database\Table\LanguagesTable;
use Inpsyde\MultilingualPress\Framework\Admin\SettingsPage;
use Inpsyde\MultilingualPress\Framework\Api\Languages;
use Inpsyde\MultilingualPress\Framework\Factory\LanguageFactory;
use Inpsyde\MultilingualPress\Framework\Factory\NonceFactory;
use Inpsyde\MultilingualPress\Framework\Http\ServerRequest;
use Inpsyde\MultilingualPress\Framework\Module\Module;
use Inpsyde\MultilingualPress\Framework\Module\ModuleManager;
use Inpsyde\MultilingualPress\Framework\Module\ModuleServiceProvider;
use Inpsyde\MultilingualPress\Framework\PluginProperties;
use Inpsyde\MultilingualPress\Framework\Service\Container;

final class ServiceProvider implements ModuleServiceProvider
{
    public const MODULE_ID = 'language-manager';

    public const MODULE_SCRIPTS_HANDLER_NAME = 'multilingualpress-language-manager';
    public const PARAMETER_CONFIG_SHOULD_ENQUEUE_MODULE_ASSETS = 'multilingualpress.languageManager.shouldEnqueueModuleAssets';
    public const CONFIGURATION_NAME_FOR_URL_TO_MODULE_ASSETS = 'multilingualpress.languageManager.urlToModuleAssets';

    /**
     * @inheritdoc
     */
    public function registerModule(ModuleManager $moduleManager): bool
    {
        return $moduleManager->register(
            new Module(
                self::MODULE_ID,
                [
                    'description' => __(
                        'Enable Language Manager to include custom languages or override existing ones.',
                        'multilingualpress'
                    ),
                    'name' => __('Language Manager', 'multilingualpress'),
                    'active' => true,
                ]
            )
        );
    }

    /**
     * @inheritdoc
     */
    public function activateModule(Container $container)
    {
        $languageManagerPage = SettingsPage::withParent(
            SettingsPage::ADMIN_NETWORK,
            SettingsPage::PARENT_MULTILINGUALPRESS,
            __('Language Manager', 'multilingualpress'),
            __('Language Manager', 'multilingualpress'),
            'manage_network_options',
            'language-manager',
            $container[PageView::class]
        );

        $requestHandler = $container->get(RequestHandler::class);

        add_action('admin_post_' . RequestHandler::ACTION, [$requestHandler, 'handlePostRequest']);
        add_action('plugins_loaded', [$languageManagerPage, 'register'], 10);

        $shouldEnqueueModuleAssets = $container->get(self::PARAMETER_CONFIG_SHOULD_ENQUEUE_MODULE_ASSETS);
        $urlToModuleAssetsFolder = $container->get(self::CONFIGURATION_NAME_FOR_URL_TO_MODULE_ASSETS);

        add_action(
            AssetManager::ACTION_SETUP,
            static function (AssetManager $assetManager) use ($urlToModuleAssetsFolder, $shouldEnqueueModuleAssets) {
                $script = new Script(self::MODULE_SCRIPTS_HANDLER_NAME, "{$urlToModuleAssetsFolder}js/admin.min.js");
                $script
                    ->withDependencies('jquery-ui-autocomplete')
                    ->withLocalize('languageManager', [
                            'newLanguageButtonLabel' => esc_html__('New Language', 'multilingualpress'),
                            'languageDeleteTableHeadLabel' => esc_html__('Delete', 'multilingualpress'),
                            'languageUndoDeleteButtonLabel' => esc_html__(
                                'Undo Delete',
                                'multilingualpress'
                            ),
                            'languageDeleteButtonLabel' => esc_html__(
                                'Delete Language',
                                'multilingualpress'
                            ),
                        ])
                    ->forLocation(Asset::BACKEND)
                    ->canEnqueue(
                        static function () use ($shouldEnqueueModuleAssets): bool {
                            return $shouldEnqueueModuleAssets;
                        }
                    );

                $style = new Style(self::MODULE_SCRIPTS_HANDLER_NAME, "{$urlToModuleAssetsFolder}css/admin.min.css");
                $style
                    ->forLocation(Asset::BACKEND)
                    ->canEnqueue(
                        static function () use ($shouldEnqueueModuleAssets): bool {
                            return $shouldEnqueueModuleAssets;
                        }
                    );

                $assetManager->register($script, $style);
            }
        );
    }

    /**
     * @inheritdoc
     *
     * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
     */
    public function register(Container $container)
    {
        // phpcs:enable

        $container->addService(
            Db::class,
            static function (Container $container): Db {
                return new Db(
                    $container[\wpdb::class],
                    $container[Languages::class],
                    $container[LanguagesTable::class]
                );
            }
        );

        $container->addService(
            TableFormView::class,
            static function (Container $container): TableFormView {
                return new TableFormView(
                    $container[Db::class],
                    $container[LanguageInstaller::class]
                );
            }
        );

        $container->addService(
            PageView::class,
            static function (Container $container): PageView {
                return new PageView(
                    $container[NonceFactory::class]->create(['save_language_manager']),
                    $container[ServerRequest::class],
                    $container[TableFormView::class]
                );
            }
        );

        $container->addService(
            LanguageInstaller::class,
            static function (): LanguageInstaller {
                return new LanguageInstaller();
            }
        );

        $container->addService(
            RequestHandler::class,
            static function (Container $container): RequestHandler {
                return new RequestHandler(
                    new Updater(
                        new Db(
                            $container[\wpdb::class],
                            $container[Languages::class],
                            $container[LanguagesTable::class]
                        ),
                        $container[LanguagesTable::class],
                        $container[LanguageFactory::class],
                        $container[LanguageInstaller::class]
                    ),
                    $container[ServerRequest::class],
                    $container[NonceFactory::class]->create(['save_language_manager'])
                );
            }
        );

        /**
         * The configuration of the URL to module assets folder.
         */
        $container->share(
            self::CONFIGURATION_NAME_FOR_URL_TO_MODULE_ASSETS,
            static function (Container $container): string {
                $pluginProperties = $container->get(PluginProperties::class);

                return $pluginProperties->dirUrl() . 'src/modules/LanguageManager/public/';
            }
        );

        /**
         * Configuration to check if the current screen is the correct one to enqueue module assets.
         */
        $container->share(
            self::PARAMETER_CONFIG_SHOULD_ENQUEUE_MODULE_ASSETS,
            static function (): bool {
                global $pagenow;

                $adminPage = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_SPECIAL_CHARS);

                return 'admin.php' === $pagenow && $adminPage === self::MODULE_ID;
            }
        );
    }
}
