<?php

namespace fluXtore\Core\Elementor;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

if ( ! class_exists( 'fluXtore_El_Css_Regenerator' ) ) {
    class fluXtore_El_Css_Regenerator {
        /**
         * Holds the singleton instance.
         *
         * @var self|null
         */
        private static $instance = null;

        private function __construct() {
            add_action( 'fluxtore/after_import_funnel', [ __CLASS__, 'regenerate_for_posts' ] );
            add_action( 'wp', [ __CLASS__, 'maybe_enqueue_post_css' ] );

            if ( defined( 'WP_CLI' ) && WP_CLI ) {
                \WP_CLI::add_command( 'fluxtore test-import-css', [ __CLASS__, 'handle_cli_test_command' ] );
            }
        }

        /**
         * Bootstraps the singleton instance.
         */
        public static function init() {
            if ( null !== self::$instance ) {
                return;
            }

            self::$instance = new self();
        }

        /**
         * Regenerates Elementor CSS for the provided post IDs.
         *
         * @param mixed $post_ids Post IDs or array of IDs.
         */
        public static function regenerate_for_posts( $post_ids ) {
            if ( empty( $post_ids ) ) {
                return;
            }

            if ( $post_ids instanceof \Traversable ) {
                $post_ids = iterator_to_array( $post_ids );
            }

            if ( ! is_array( $post_ids ) ) {
                $post_ids = [ $post_ids ];
            }

            $post_ids = array_values( array_unique( array_filter( array_map( 'absint', $post_ids ) ) ) );

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

            if ( ! class_exists( '\\Elementor\\Plugin' ) ) {
                self::log( 'Skipped Elementor CSS regeneration because Elementor is not active.' );
                return;
            }

            $plugin = \Elementor\Plugin::$instance;

            if ( ! $plugin ) {
                self::log( 'Skipped Elementor CSS regeneration because the Elementor plugin instance is not available.' );
                return;
            }

            self::log( 'Starting Elementor CSS regeneration for posts: ' . implode( ', ', $post_ids ) );

            self::maybe_clear_files_manager_cache( $plugin );

            foreach ( $post_ids as $post_id ) {
                if ( ! self::prepare_elementor_meta( $post_id ) ) {
                    self::log( sprintf( 'Skipping Elementor CSS regeneration for post %d: no Elementor data found.', $post_id ) );
                    continue;
                }

                self::clear_cache_for_post( $plugin, $post_id );
                self::regenerate_post_css( $post_id );
            }

            self::regenerate_active_kit_stylesheet( $plugin );
            self::maybe_clear_files_manager_cache( $plugin );

            self::log( 'Finished Elementor CSS regeneration.' );
        }

        /**
         * Ensures Elementor meta is normalized before regeneration.
         *
         * @param int $post_id Post ID.
         *
         * @return bool
         */
        private static function prepare_elementor_meta( $post_id ) {
            $raw_data = get_post_meta( $post_id, '_elementor_data', true );

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

            $normalized = self::normalize_elementor_data( $raw_data );

            if ( '' === $normalized ) {
                self::log( sprintf( 'Elementor data could not be normalized for post %d.', $post_id ) );
                return false;
            }

            update_post_meta( $post_id, '_elementor_data', $normalized );
            update_post_meta( $post_id, '_elementor_edit_mode', 'builder' );

            if ( defined( 'ELEMENTOR_VERSION' ) ) {
                update_post_meta( $post_id, '_elementor_version', ELEMENTOR_VERSION );
            }

            delete_post_meta( $post_id, '_elementor_css' );
            delete_post_meta( $post_id, '_elementor_page_assets' );

            return true;
        }

        /**
         * Normalizes Elementor data into a JSON string.
         *
         * @param mixed $data Raw Elementor data.
         *
         * @return string
         */
        private static function normalize_elementor_data( $data ) {
            if ( is_array( $data ) ) {
                $encoded = wp_json_encode( $data );

                return is_string( $encoded ) ? $encoded : '';
            }

            if ( is_string( $data ) ) {
                $data    = wp_unslash( $data );
                $decoded = json_decode( $data, true );

                if ( JSON_ERROR_NONE === json_last_error() && is_array( $decoded ) ) {
                    $encoded = wp_json_encode( $decoded );

                    return is_string( $encoded ) ? $encoded : '';
                }

                $maybe_unserialized = maybe_unserialize( $data );

                if ( is_array( $maybe_unserialized ) ) {
                    $encoded = wp_json_encode( $maybe_unserialized );

                    return is_string( $encoded ) ? $encoded : '';
                }
            }

            return '';
        }

        /**
         * Regenerates the Elementor CSS file for a specific post.
         *
         * @param int $post_id Post ID.
         */
        private static function regenerate_post_css( $post_id ) {
            $css_class = '\\Elementor\\Core\\Files\\CSS\\Post';

            if ( ! class_exists( $css_class ) ) {
                self::log( sprintf( 'Elementor CSS class missing, cannot regenerate for post %d.', $post_id ) );
                return;
            }

            try {
                $css_file = $css_class::create( $post_id );

                if ( $css_file && method_exists( $css_file, 'update' ) ) {
                    $css_file->update();
                    self::log( sprintf( 'Elementor CSS regenerated for post %d.', $post_id ) );
                } elseif ( $css_file && method_exists( $css_file, 'enqueue' ) ) {
                    $css_file->enqueue();
                    self::log( sprintf( 'Elementor CSS enqueued for post %d because update() is unavailable.', $post_id ) );
                } else {
                    self::log( sprintf( 'Unable to regenerate Elementor CSS for post %d.', $post_id ) );
                }
            } catch ( \Throwable $exception ) {
                self::log( sprintf( 'Failed to regenerate Elementor CSS for post %d: %s', $post_id, $exception->getMessage() ) );
            }
        }

        /**
         * Clears Elementor's global CSS cache when possible.
         *
         * @param \Elementor\Plugin $plugin Elementor plugin instance.
         */
        private static function maybe_clear_files_manager_cache( $plugin ) {
            $files_manager = isset( $plugin->files_manager ) ? $plugin->files_manager : null;

            if ( ! $files_manager ) {
                return;
            }

            if ( method_exists( $files_manager, 'clear_cache' ) ) {
                $files_manager->clear_cache();
            }
        }

        /**
         * Clears Elementor CSS cache for a specific post.
         *
         * @param \Elementor\Plugin $plugin  Elementor plugin instance.
         * @param int                $post_id Post ID.
         */
        private static function clear_cache_for_post( $plugin, $post_id ) {
            $files_manager = isset( $plugin->files_manager ) ? $plugin->files_manager : null;

            if ( ! $files_manager ) {
                return;
            }

            if ( method_exists( $files_manager, 'clear_cache_for_post' ) ) {
                $files_manager->clear_cache_for_post( $post_id );
            }
        }

        /**
         * Regenerates the active Elementor Kit stylesheet.
         *
         * @param \Elementor\Plugin $plugin Elementor plugin instance.
         */
        private static function regenerate_active_kit_stylesheet( $plugin ) {
            $manager = isset( $plugin->kits_manager ) ? $plugin->kits_manager : null;

            if ( ! $manager ) {
                self::log( 'Elementor kits manager missing, skipping kit stylesheet regeneration.' );
                return;
            }

            $kit = null;

            if ( method_exists( $manager, 'get_active_kit_for_frontend' ) ) {
                $kit = $manager->get_active_kit_for_frontend();
            } elseif ( method_exists( $manager, 'get_active_kit' ) ) {
                $kit = $manager->get_active_kit();
            }

            if ( ! $kit || ! method_exists( $kit, 'get_stylesheet' ) ) {
                self::log( 'No active Elementor Kit stylesheet available for regeneration.' );
                return;
            }

            $stylesheet = $kit->get_stylesheet();

            if ( $stylesheet && method_exists( $stylesheet, 'update' ) ) {
                $stylesheet->update();
                self::log( 'Elementor Kit stylesheet regenerated.' );
            }
        }

        /**
         * Ensures Elementor CSS is enqueued on singular funnel pages.
         */
        public static function maybe_enqueue_post_css() {
            if ( ! is_singular() ) {
                return;
            }

            $post_id = get_queried_object_id();

            if ( ! $post_id ) {
                return;
            }

            $post_type = get_post_type( $post_id );

            if ( ! in_array( $post_type, [ defined( 'FLUXTORE_FLOW' ) ? FLUXTORE_FLOW : 'fluxtore_flow', defined( 'FLUXTORE_STEP' ) ? FLUXTORE_STEP : 'fluxtore_step' ], true ) ) {
                return;
            }

            $css_class = '\\Elementor\\Core\\Files\\CSS\\Post';

            if ( ! class_exists( $css_class ) ) {
                return;
            }

            try {
                $css_file = $css_class::create( $post_id );

                if ( $css_file && method_exists( $css_file, 'enqueue' ) ) {
                    $css_file->enqueue();
                }
            } catch ( \Throwable $exception ) {
                self::log( sprintf( 'Failed to enqueue Elementor CSS for post %d: %s', $post_id, $exception->getMessage() ) );
            }
        }

        /**
         * WP-CLI smoke test command to regenerate CSS for the latest funnel.
         */
        public static function handle_cli_test_command() {
            if ( ! class_exists( '\\Elementor\\Plugin' ) ) {
                \WP_CLI::warning( 'Elementor is not active; skipping CSS regeneration.' );

                return;
            }

            $latest = get_posts(
                [
                    'post_type'      => defined( 'FLUXTORE_FLOW' ) ? FLUXTORE_FLOW : 'fluxtore_flow',
                    'posts_per_page' => 1,
                    'orderby'        => 'date',
                    'order'          => 'DESC',
                    'post_status'    => 'any',
                ]
            );

            if ( empty( $latest ) ) {
                \WP_CLI::warning( 'No funnels available to regenerate.' );
                return;
            }

            $funnel = $latest[0];
            $steps  = get_post_meta( $funnel->ID, '__fluxtore__steps', true );

            if ( ! is_array( $steps ) ) {
                $steps = [];
            }

            $post_ids = array_merge( [ $funnel->ID ], array_map( 'absint', $steps ) );

            self::regenerate_for_posts( $post_ids );

            \WP_CLI::success(
                sprintf(
                    'Triggered Elementor CSS regeneration for funnel %d and %d step(s).',
                    $funnel->ID,
                    count( $steps )
                )
            );
        }

        /**
         * Logs debug messages when WP_DEBUG is enabled.
         *
         * @param string $message Message to log.
         */
        private static function log( $message ) {
            if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
                error_log( '[fluxtore] ' . $message );
            }
        }
    }
}

fluXtore_El_Css_Regenerator::init();
