<?php

declare(strict_types=1);

namespace Inpsyde\MultilingualPress\Module\QuickLinks;

use Inpsyde\Assets\Asset;
use Inpsyde\Assets\AssetManager;
use Inpsyde\Assets\Script;
use Inpsyde\Assets\Style;
use Inpsyde\MultilingualPress\Core\Admin\PluginSettingsUpdater;
use Inpsyde\MultilingualPress\Core\Admin\SiteSettingsRepository;
use Inpsyde\MultilingualPress\Core\ServiceProvider as CoreServiceProvider;
use Inpsyde\MultilingualPress\Framework\Admin\SettingsPageTab;
use Inpsyde\MultilingualPress\Framework\Admin\SettingsPageTabData;
use Inpsyde\MultilingualPress\Framework\Api\ContentRelations;
use Inpsyde\MultilingualPress\Framework\Api\Translations;
use Inpsyde\MultilingualPress\Framework\Factory\NonceFactory;
use Inpsyde\MultilingualPress\Framework\Module\Exception\ModuleAlreadyRegistered;
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;
use Inpsyde\MultilingualPress\Module\QuickLinks\Model\CollectionFactory;
use Inpsyde\MultilingualPress\Module\QuickLinks\Settings\QuickLinksPositionViewModel;
use Inpsyde\MultilingualPress\Module\QuickLinks\Settings\Repository;
use Inpsyde\MultilingualPress\Module\QuickLinks\Settings\TabView;
use Inpsyde\MultilingualPress\Module\QuickLinks\Settings\Updater;
use wpdb;

use function Inpsyde\MultilingualPress\assignedLanguageNames;

class ServiceProvider implements ModuleServiceProvider
{
    public const MODULE_ID = 'quick_links';
    public const MODULE_SETTINGS_TAB_NAME = 'quick-links';

    public const MODULE_SCRIPTS_HANDLER_NAME = 'multilingualpress-quicklinks';
    public const PARAMETER_CONFIG_SHOULD_ENQUEUE_MODULE_ASSETS = 'multilingualpress.quickLinks.shouldEnqueueModuleAssets';
    public const CONFIGURATION_NAME_FOR_URL_TO_MODULE_ASSETS = 'multilingualpress.quickLinks.urlToModuleAssets';

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

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

        $container->addService(
            Redirector::class,
            static function (Container $container): Redirector {
                return new Redirector(
                    $container[NonceFactory::class]->create(['quicklinks_redirector'])
                );
            }
        );

        $container->share(
            CollectionFactory::class,
            static function (Container $container): CollectionFactory {
                return new CollectionFactory(
                    $container->get(ContentRelations::class),
                    $container->get(SiteSettingsRepository::class),
                    $container->get(Translations::class)
                );
            }
        );

        $container->addService(
            QuickLink::class,
            static function (Container $container): QuickLink {
                return new QuickLink(
                    $container[CollectionFactory::class],
                    $container[NonceFactory::class]->create(['quicklinks_redirector']),
                    $container[Repository::class],
                    assignedLanguageNames()
                );
            }
        );

        /* ----------------------------------------------------
           Settings
           ------------------------------------------------- */

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

        $container->addService(
            Settings\Updater::class,
            static function (Container $container): Settings\Updater {
                return new Settings\Updater(
                    $container[NonceFactory::class]->create(['save_module_quicklinks_settings']),
                    $container[Repository::class]
                );
            }
        );

        /**
         * 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/QuickLinks/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);
                $tab = filter_input(INPUT_GET, 'tab', FILTER_SANITIZE_SPECIAL_CHARS);
                $isQuickLinksTab = $adminPage === 'multilingualpress' && $tab === self::MODULE_SETTINGS_TAB_NAME;

                return 'admin.php' === $pagenow && $isQuickLinksTab;
            }
        );

        add_filter(
            CoreServiceProvider::ACTION_BUILD_TABS,
            static function (array $tabs) use ($container) {

                $settingsRepository = $container[Repository::class];
                $nonceFactory = $container[NonceFactory::class];
                $moduleManager = $container[ModuleManager::class];

                if ($moduleManager->isModuleActive(self::MODULE_ID)) {
                    $tabs[self::MODULE_SETTINGS_TAB_NAME] = new SettingsPageTab(
                        new SettingsPageTabData(
                            'quicklinks',
                            esc_html_x(
                                'QuickLinks',
                                'QuickLinks Module Settings',
                                'multilingualpress'
                            ),
                            'quicklinks'
                        ),
                        new TabView(
                            $nonceFactory->create(['save_module_quicklinks_settings']),
                            new QuickLinksPositionViewModel($settingsRepository)
                        )
                    );
                }

                return $tabs;
            }
        );
    }

    /**
     * @inheritDoc
     * @throws ModuleAlreadyRegistered
     */
    public function registerModule(ModuleManager $moduleManager): bool
    {
        return $moduleManager->register(
            new Module(
                self::MODULE_ID,
                [
                    'description' => __(
                        'Show link to translations in post content.',
                        'multilingualpress'
                    ),
                    'name' => __('QuickLink', 'multilingualpress'),
                    'active' => false,
                ]
            )
        );
    }

    /**
     * @inheritDoc
     */
    public function activateModule(Container $container)
    {
        $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) {
                $assetHandlerNamePrefix = self::MODULE_SCRIPTS_HANDLER_NAME;
                $adminAssetHandlerName = "{$assetHandlerNamePrefix}-admin";
                $frontendAssetHandlerName = "{$assetHandlerNamePrefix}-frontend";

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

                $frontendStyle = new Style($frontendAssetHandlerName, "{$urlToModuleAssetsFolder}css/frontend.min.css");
                $frontendStyle
                    ->forLocation(Asset::FRONTEND)
                    ->canEnqueue(
                        static function (): bool {
                            return is_singular();
                        }
                    );

                $frontendScript = new Script($frontendAssetHandlerName, "{$urlToModuleAssetsFolder}js/frontend.min.js");
                $frontendScript
                    ->forLocation(Asset::FRONTEND)
                    ->canEnqueue(
                        static function (): bool {
                            return is_singular();
                        }
                    );

                $assetManager->register($adminStyle, $frontendStyle, $frontendScript);
            }
        );

        add_action(PluginSettingsUpdater::ACTION_UPDATE_PLUGIN_SETTINGS, [$container->get(Updater::class), 'updateSettings']);
        add_filter('the_content', [$container->get(QuickLink::class), 'filter']);
        add_action('wp_loaded', [$container->get(Redirector::class), 'redirect']);

        $filter = $container->get(ValidateRedirectFilter::class);
        $filter->enable();
        add_action(Redirector::ACTION_AFTER_VALIDATE_REDIRECT, [$filter, 'disable']);
    }
}
