<?php

declare(strict_types=1);

namespace Inpsyde\MultilingualPress\Module\Trasher;

use Inpsyde\Assets\Asset;
use Inpsyde\Assets\AssetManager;
use Inpsyde\Assets\Script;
use Inpsyde\MultilingualPress\Core\Entity\ActivePostTypes;
use Inpsyde\MultilingualPress\Framework\Api\ContentRelations;
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;

use function Inpsyde\MultilingualPress\wpHookProxy;

final class ServiceProvider implements ModuleServiceProvider
{
    public const MODULE_ID = 'trasher';
    public const MODULE_ASSETS_FACTORY_SERVICE_NAME = 'trasher_asset_factory';
    protected const NONCE_ACTION = 'save_trasher_setting';
    public const CONFIGURATION_NAME_FOR_URL_TO_MODULE_ASSETS = 'multilingualpress.trasher.urlToModuleAssets';

    /**
     * @inheritdoc
     */
    public function register(Container $container)
    {
        $container->share(
            TrasherSettingRepository::class,
            static function (): TrasherSettingRepository {
                return new TrasherSettingRepository();
            }
        );

        $container->addService(
            Trasher::class,
            static function (Container $container): Trasher {
                return new Trasher(
                    $container[TrasherSettingRepository::class],
                    $container[ContentRelations::class],
                    $container[ActivePostTypes::class]
                );
            }
        );

        $container->addService(
            TrasherSettingUpdater::class,
            static function (Container $container): TrasherSettingUpdater {
                return new TrasherSettingUpdater(
                    $container[TrasherSettingRepository::class],
                    $container[ContentRelations::class],
                    $container[ServerRequest::class],
                    $container[NonceFactory::class]->create([self::NONCE_ACTION]),
                    $container[ActivePostTypes::class]
                );
            }
        );

        $container->addService(
            TrasherSettingView::class,
            static function (Container $container): TrasherSettingView {
                return new TrasherSettingView(
                    $container[TrasherSettingRepository::class],
                    $container[NonceFactory::class]->create([self::NONCE_ACTION]),
                    $container[ActivePostTypes::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/Trasher/public/';
            }
        );
    }

    /**
     * @inheritdoc
     */
    public function registerModule(ModuleManager $moduleManager): bool
    {
        return $moduleManager->register(
            new Module(
                self::MODULE_ID,
                [
                    'description' => __(
                        'Enable the Thrash checkbox on post/page edit page: this allows you to send all the translations to trash when the source post/page is trashed.',
                        'multilingualpress'
                    ),
                    'name' => __('Trasher', 'multilingualpress'),
                    'active' => false,
                ]
            )
        );
    }

    /**
     * @inheritdoc
     */
    public function activateModule(Container $container)
    {
        $trasher = $container->get(Trasher::class);

        add_action('init', static function () {
            register_meta('post', '_trash_the_other_posts', [
                'show_in_rest' => true,
                'single' => true,
                'type' => 'boolean',
                'auth_callback' => '__return_true',
            ]);
        });

        add_action('wp_trash_post', wpHookProxy([$trasher, 'trashRelatedPosts']));

        if (!(is_admin() || wp_doing_ajax())) {
            return;
        }

        $trasherSettingUpdater = $container->get(TrasherSettingUpdater::class);
        $trasherSettingView = $container->get(TrasherSettingView::class);
        $urlToModuleAssetsFolder = $container->get(self::CONFIGURATION_NAME_FOR_URL_TO_MODULE_ASSETS);

        add_action('post_submitbox_misc_actions', wpHookProxy([$trasherSettingView, 'render']));
        add_action('save_post', wpHookProxy([$trasherSettingUpdater, 'update']), 10, 2);

        add_action(
            AssetManager::ACTION_SETUP,
            // phpcs:disable Inpsyde.CodeQuality.LineLength.TooLong
            static function (AssetManager $assetManager) use ($urlToModuleAssetsFolder) {
                $trasherScript = new Script('multilingualpress-trasher', "{$urlToModuleAssetsFolder}js/admin.min.js");
                $trasherScript
                    ->withDependencies('wp-i18n', 'wp-element', 'wp-editor', 'wp-plugins', 'wp-edit-post')
                    ->withLocalize('trasherSettings', [
                        'checkboxLabel' => __('Send all the translations to trash when this post is trashed.', 'multilingualpress'),
                        ])
                    ->forLocation(Asset::BACKEND)
                    ->canEnqueue(
                        static function (): bool {
                            global $pagenow;
                            return in_array($pagenow, ['post.php', 'post-new.php'], true);
                        }
                    );

                $assetManager->register($trasherScript);
            }
            // phpcs:enable
        );

        add_filter(
            ActivePostTypes::FILTER_ACTIVE_POST_TYPES,
            function ($postTypes) use ($trasherSettingUpdater) {
                foreach ($postTypes as $postType) {
                    $this->addRestInsertAction(strval($postType), $trasherSettingUpdater);
                }
                return $postTypes;
            }
        );
    }

    /**
     * @param string $postType
     * @param TrasherSettingUpdater $trasherSettingUpdater
     * @return void
     */
    private function addRestInsertAction(
        string $postType,
        TrasherSettingUpdater $trasherSettingUpdater
    ) {

        if (post_type_supports($postType, 'custom-fields')) {
            add_action(
                "rest_insert_{$postType}",
                [$trasherSettingUpdater, 'updateFromRestApi'],
                10,
                2
            );
        }
    }
}
