<?php

namespace PublishPress\FuturePro\Controllers;

use Closure;
use PublishPress\Future\Core\HookableInterface;
use PublishPress\Future\Core\HooksAbstract as CoreHooksAbstract;
use PublishPress\Future\Framework\ModuleInterface;
use PublishPress\Future\Modules\Expirator\ExpirationActionsAbstract;
use PublishPress\Future\Modules\Expirator\HooksAbstract as ExpiratorHooksAbstract;
use PublishPress\Future\Modules\Expirator\Interfaces\SchedulerInterface;
use PublishPress\Future\Modules\Expirator\Models\ExpirablePostModel;
use PublishPress\Future\Modules\Expirator\Models\PostTypeDefaultDataModelFactory;
use PublishPress\Future\Modules\Expirator\PostMetaAbstract;
use PublishPress\FuturePro\Core\HooksAbstract;
use PublishPress\FuturePro\Models\SettingsModel;

defined('ABSPATH') or die('No direct script access allowed.');

class MetadataMappingController implements ModuleInterface
{
    /**
     * @var \PublishPress\Future\Core\HookableInterface
     */
    private $hooks;

    /**
     * @var \PublishPress\FuturePro\Models\SettingsModel
     */
    private $settingsModel;

    /**
     * @var Closure
     */
    private $postModelFactory;

    /**
     * @var \PublishPress\Future\Modules\Expirator\Interfaces\SchedulerInterface
     */
    private $scheduler;

    /**
     * This is true when a WP import is running.
     *
     * @var bool
     */
    private $importIsRunning = false;

    /**
     * Stores the list of post IDs that were imported during the current import process.
     *
     * @var array
     */
    private $importedPostIDs = [];

    /**
     * @var \PublishPress\Future\Modules\Expirator\Models\PostTypeDefaultDataModelFactory
     */
    private $defaultDataModelFactory;

    /**
     * This is true when a WebToffee Import/Export for WooCommerce import is running.
     *
     * @var bool
     */
    private $webToffeeImportIsRunning = false;

    public function __construct(
        HookableInterface $hooks,
        SettingsModel $settingsModel,
        Closure $postModelFactory,
        SchedulerInterface $scheduler,
        PostTypeDefaultDataModelFactory $postTypeDefaultDataModelFactory
    ) {
        $this->hooks = $hooks;
        $this->settingsModel = $settingsModel;
        $this->postModelFactory = $postModelFactory;
        $this->scheduler = $scheduler;
        $this->defaultDataModelFactory = $postTypeDefaultDataModelFactory;
    }

    public function initialize()
    {
        $this->hooks->addAction(
            HooksAbstract::ACTION_IMPORT_START,
            [$this, 'onImportStart']
        );

        $this->hooks->addAction(
            HooksAbstract::ACTION_IMPORT_END,
            [$this, 'onImportEnd']
        );

        $this->hooks->addAction(
            CoreHooksAbstract::ACTION_SAVE_POST,
            [$this, 'onSavePost'],
            10,
            2
        );

        $this->hooks->addAction(
            HooksAbstract::ACTION_PROCESS_METADATA,
            [$this, 'processMetadataDrivenScheduling'],
            10,
            2
        );

        $this->hooks->addFilter(
            ExpiratorHooksAbstract::FILTER_ACTION_META_KEY,
            [$this, 'filterMetaKey'],
            10,
            2
        );

        $this->hooks->addFilter(
            ExpiratorHooksAbstract::FILTER_HIDE_METABOX,
            [$this, 'filterHideMetabox'],
            10,
            2
        );

        $this->hooks->addFilter(
            ExpiratorHooksAbstract::FILTER_DISPLAY_BULK_ACTION_SYNC,
            [$this, 'filterDisplayBulkActionSync'],
            10,
            2
        );

        $this->hooks->addAction(
            HooksAbstract::ACTION_WOOCOMMERCE_AFTER_PRODUCT_OBJECT_SAVE,
            [$this, 'onWooCommerceProductSave']
        );

        /**
         * Fix import issue with WebToffee Import/Export for WooCommerce.
         *
         * @see https://github.com/publishpress/PublishPress-Future/issues/1181
         */
        $this->hooks->addAction(
            'wt_woocommerce_product_import_before_process_item',
            [$this, 'setWebToffeeImportRunningFlag'],
            -1
        );

        $this->hooks->addFilter(
            'wt_woocommerce_product_import_inserted_product_object',
            [$this, 'processMetadataDrivenSchedulingByWebToffeeImporter'],
            -1
        );
    }

    public function onImportStart()
    {
        $this->importIsRunning = true;
        $this->importedPostIDs = [];
    }

    public function onImportEnd()
    {
        $this->importIsRunning = false;

        if (empty($this->importedPostIDs)) {
            return;
        }

        foreach ($this->importedPostIDs as $postId) {
            $this->hooks->doAction(HooksAbstract::ACTION_PROCESS_METADATA, $postId);
        }
    }

    public function onSavePost($postId, $post)
    {
        if ($this->webToffeeImportIsRunning) {
            return;
        }

        if ($this->importIsRunning) {
            $this->importedPostIDs[] = $postId;

            return;
        }

        $this->hooks->doAction(HooksAbstract::ACTION_PROCESS_METADATA, $postId, $post);
    }

    private function getActionDateFromMetadata($postId)
    {
        $postModel = ($this->postModelFactory)($postId);
        $timestamp = $postModel->getMeta(PostMetaAbstract::EXPIRATION_TIMESTAMP, true);

        return $timestamp;
    }

    public function processMetadataDrivenScheduling($postId, $post = null)
    {
        if (empty($post)) {
            $post = get_post($postId);
        }

        if (empty($post) || ! $post instanceof \WP_Post) {
            return;
        }

        // Check if the post type has metadata mapping enabled.
        $postType = $post->post_type;
        $statuses = $this->settingsModel->getMetadataMappingStatus();

        if (! array_key_exists($postType, $statuses) || $statuses[$postType] !== true) {
            return;
        }

        $postModel = ($this->postModelFactory)($postId);

        $timestamp = $postModel->getMeta(PostMetaAbstract::EXPIRATION_TIMESTAMP, true);

        if (empty($timestamp)) {
            return;
        }

        $this->garanteeActionDataWithDefaultData($postId);

        $metadataHash = $postModel->calcMetadataHash();

        // Check if the flag is set to avoid infinite loops.
        if ($metadataHash === $postModel->getMetadataHash()) {
            return;
        }

        $postModel->syncScheduleWithPostMeta();

        // Set the flag to avoid infinite loops.
        $postModel->updateMetadataHash($metadataHash);
    }

    private function garanteeActionDataWithDefaultData($postId): bool
    {
        $postModel = ($this->postModelFactory)($postId);
        $timestamp = $postModel->getMeta(PostMetaAbstract::EXPIRATION_TIMESTAMP, true);

        if (empty($timestamp)) {
            return false;
        }

        $defaultDataModel = $this->defaultDataModelFactory->create($postModel->getPostType());

        $action = $postModel->getMeta(PostMetaAbstract::EXPIRATION_TYPE, true);
        if (empty($action)) {
            $postModel->updateMeta(PostMetaAbstract::EXPIRATION_TYPE, $defaultDataModel->getAction());
        }

        $newStatus = $postModel->getMeta(PostMetaAbstract::EXPIRATION_POST_STATUS, true);
        if (empty($newStatus)) {
            $postModel->updateMeta(PostMetaAbstract::EXPIRATION_POST_STATUS, $defaultDataModel->getNewStatus());
        }

        $status = $postModel->getMeta(PostMetaAbstract::EXPIRATION_STATUS, true);
        if (empty($status)) {
            $postModel->updateMeta(PostMetaAbstract::EXPIRATION_STATUS, 1);
        }

        $termRelatedAction = [
            ExpirationActionsAbstract::POST_CATEGORY_REMOVE,
            ExpirationActionsAbstract::POST_CATEGORY_ADD,
            ExpirationActionsAbstract::POST_CATEGORY_REMOVE_ALL,
            ExpirationActionsAbstract::POST_CATEGORY_SET,
        ];

        if (in_array($action, $termRelatedAction)) {
            $taxonomy = $postModel->getMeta(PostMetaAbstract::EXPIRATION_TAXONOMY, true);
            if (empty($taxonomy)) {
                $postModel->updateMeta(PostMetaAbstract::EXPIRATION_TAXONOMY, $defaultDataModel->getTaxonomy());
            }

            $terms = $postModel->getMeta(PostMetaAbstract::EXPIRATION_TERMS, true);
            if (empty($terms)) {
                $postModel->updateMeta(PostMetaAbstract::EXPIRATION_TERMS, $defaultDataModel->getTerms());
            }
        }

        return true;
    }

    /**
     * @param string $metaKey
     * @param int $postId
     */
    public function filterMetaKey($metaKey, $postId): string
    {
        if (empty($metaKey)) {
            return $metaKey;
        }

        $mapping = $this->settingsModel->getMetadataMapping();

        if (empty($mapping)) {
            return $metaKey;
        }

        $postType = get_post_type($postId);

        $statusPerPostType = $this->settingsModel->getMetadataMappingStatus();
        if (! array_key_exists($postType, $statusPerPostType) || $statusPerPostType[$postType] !== true) {
            return $metaKey;
        }

        if (empty($postType) || ! array_key_exists($postType, $mapping)) {
            return $metaKey;
        }

        $mappedMetaKey = $mapping[$postType][$metaKey] ?? $metaKey;

        if (empty($mappedMetaKey)) {
            return $metaKey;
        }

        return $mappedMetaKey;
    }

    public function filterHideMetabox($hideMetabox, $postType): bool
    {
        $statusPerPostType = $this->settingsModel->getMetaboxHideStatus();

        if (array_key_exists($postType, $statusPerPostType)) {
            return (bool)$statusPerPostType[$postType];
        }

        return $hideMetabox;
    }

    public function filterDisplayBulkActionSync($displayBulkActionSync, $postType): bool
    {
        $statusPerPostType = $this->settingsModel->getMetadataMappingStatus();

        if (array_key_exists($postType, $statusPerPostType)) {
            return (bool)$statusPerPostType[$postType];
        }

        return $displayBulkActionSync;
    }

    public function onWooCommerceProductSave($product)
    {
        if ($this->webToffeeImportIsRunning) {
            return;
        }

        $this->hooks->doAction(HooksAbstract::ACTION_PROCESS_METADATA, $product->get_id());
    }

    public function setWebToffeeImportRunningFlag($data)
    {
        $this->webToffeeImportIsRunning = true;
    }

    public function processMetadataDrivenSchedulingByWebToffeeImporter($data)
    {
        $this->webToffeeImportIsRunning = false;

        $this->hooks->doAction(HooksAbstract::ACTION_PROCESS_METADATA, $data->get_id());
    }
}
