<?php

namespace fluXtore\Core\Admin\Ajax;

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

if ( ! class_exists( 'fluXtore_Ajax_Funnels' ) ) {
    class fluXtore_Ajax_Funnels {
        /**
         * @var self|null
         */
        private static $instance = null;

        private function __construct() {}

        public static function init() {
            if ( null !== self::$instance ) {
                return;
            }

            self::$instance = new self();
            self::$instance->register_actions();
        }

        private function register_actions() {
            add_action( 'init', [ $this, 'increase_packet_size' ] );

            add_action( 'wp_ajax_import_funnel_data', [ $this, 'import_funnel_data' ] );
            add_action( 'wp_ajax_nopriv_import_funnel_data', [ $this, 'import_funnel_data' ] );

            add_action( 'wp_ajax_upload_funnel_json', [ $this, 'handle_chunked_upload' ] );
            add_action( 'wp_ajax_nopriv_upload_funnel_json', [ $this, 'handle_chunked_upload' ] );
        }

        public function increase_packet_size() {
            if ( ! wp_doing_ajax() ) {
                return;
            }

            $action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : '';

            if ( ! in_array( $action, [ 'import_funnel_data', 'upload_funnel_json' ], true ) ) {
                return;
            }

            global $wpdb;

            $desired_packet_size = 1024 * 1024 * 1024;
            $current_packet_size = (int) $wpdb->get_var( 'SELECT @@session.max_allowed_packet' );
            $global_packet_size  = (int) $wpdb->get_var( 'SELECT @@global.max_allowed_packet' );

            if ( $current_packet_size >= $desired_packet_size ) {
                return;
            }

            $target_packet_size = $desired_packet_size;

            if ( $global_packet_size > 0 ) {
                $target_packet_size = min( $desired_packet_size, $global_packet_size );
            }

            $target_packet_size = absint( $target_packet_size );

            if ( $target_packet_size <= 0 || $current_packet_size >= $target_packet_size ) {
                return;
            }

            $previous_suppression = $wpdb->suppress_errors( true );
            $wpdb->query( 'SET SESSION max_allowed_packet = ' . $target_packet_size );
            $wpdb->suppress_errors( $previous_suppression );
        }

        public function import_funnel_data() {
            $funnels = isset( $_POST['funnels'] ) ? json_decode( stripslashes( wp_unslash( $_POST['funnels'] ) ), true ) : [];

            if ( empty( $funnels ) || ! is_array( $funnels ) ) {
                wp_send_json_error( __( 'No funnels selected.', 'fluxtore' ) );
            }

            if ( ob_get_length() ) {
                ob_end_clean();
            }

            $post_ids = array_column( $funnels, 'id' );

            $posts = get_posts(
                [
                    'post_type'   => 'fluxtore_flow',
                    'post__in'    => $post_ids,
                    'orderby'     => 'post__in',
                    'numberposts' => -1,
                ]
            );

            $export_data = [];

            foreach ( $post_ids as $post_id ) {
                $main_post = get_post( $post_id );

                if ( ! $main_post ) {
                    continue;
                }

                $steps_serialized = get_post_meta( $post_id, '__fluxtore__steps', true );
                $flux_visitor     = get_post_meta( $post_id, '__fluxtore__visitors', true );
                $step_ids         = maybe_unserialize( $steps_serialized );

                $posts_steps = [];
                $steps_data  = [];

                if ( is_array( $step_ids ) && ! empty( $step_ids ) ) {
                    $posts_steps = get_posts(
                        [
                            'post_type'   => 'fluxtore_step',
                            'post__in'    => $step_ids,
                            'orderby'     => 'post__in',
                            'numberposts' => -1,
                        ]
                    );

                    foreach ( $step_ids as $step_id ) {
                        $step_post = get_post( $step_id );

                        if ( $step_post ) {
                            $elementor_css_posts = get_posts(
                                [
                                    'post_type'   => 'elementor_css',
                                    'post_parent' => $step_id,
                                    'post_status' => 'any',
                                    'numberposts' => -1,
                                ]
                            );

                            $elementor_css_data = [];

                            if ( ! empty( $elementor_css_posts ) ) {
                                foreach ( $elementor_css_posts as $css_post ) {
                                    $elementor_css_data[] = [
                                        'post' => get_object_vars( $css_post ),
                                        'meta' => get_post_meta( $css_post->ID ),
                                    ];
                                }
                            }

                            $steps_data[] = [
                                'post_id'       => $step_id,
                                'title'         => get_the_title( $step_id ),
                                'permalink'     => get_permalink( $step_id ),
                                'meta'          => get_post_meta( $step_id ),
                                'elementor_css' => $elementor_css_data,
                            ];
                        }
                    }
                }

                $export_data[] = [
                    'post_id'     => $post_id,
                    'post'        => get_object_vars( $main_post ),
                    'posts_steps' => $posts_steps,
                    'visitors'    => $flux_visitor,
                    'steps'       => $steps_data,
                ];
            }

            if ( empty( $export_data ) ) {
                wp_send_json_error( __( 'No steps found or invalid data.', 'fluxtore' ) );
            }

            wp_send_json_success( $export_data );
        }

        public function handle_chunked_upload() {
            $chunk        = isset( $_POST['chunk'] ) ? wp_unslash( $_POST['chunk'] ) : '';
            $chunk_index  = isset( $_POST['chunk_index'] ) ? intval( $_POST['chunk_index'] ) : 0;
            $total_chunks = isset( $_POST['total_chunks'] ) ? intval( $_POST['total_chunks'] ) : 0;
            $file_name    = isset( $_POST['file_name'] ) ? sanitize_text_field( wp_unslash( $_POST['file_name'] ) ) : '';
            $file_type    = isset( $_POST['file_type'] ) ? sanitize_text_field( wp_unslash( $_POST['file_type'] ) ) : '';

            if ( 'application/json' !== $file_type ) {
                wp_send_json_error( __( 'Invalid file type. Please upload a .json file', 'fluxtore' ) );
            }

            $temp_key      = 'chunked_json_file_' . get_current_user_id();
            $existing_data = get_option( $temp_key, '' );
            $updated_data  = $existing_data . $chunk;

            update_option( $temp_key, $updated_data );

            if ( $chunk_index + 1 !== $total_chunks ) {
                wp_send_json_success( [ 'message' => __( 'Chunk received.', 'fluxtore' ) ] );
            }

            $decoded = json_decode( $updated_data, true );

            if ( json_last_error() !== JSON_ERROR_NONE || ! is_array( $decoded ) ) {
                delete_option( $temp_key );
                wp_send_json_error( __( 'Invalid JSON format.', 'fluxtore' ) );
            }

            if ( is_array( $decoded ) && ! wp_is_numeric_array( $decoded ) ) {
                $decoded = [ $decoded ];
            }

            $processed          = 0;
            $total              = count( $decoded );
            $regeneration_queue = [];

            foreach ( $decoded as $item ) {
                if ( empty( $item['post']['post_type'] ) || 'fluxtore_flow' !== $item['post']['post_type'] ) {
                    continue;
                }

                $title    = $item['post']['post_title'];
                $existing = get_posts(
                    [
                        'post_type'   => 'fluxtore_flow',
                        'title'       => $title,
                        'post_status' => 'publish',
                    ]
                );

                if ( ! empty( $existing ) ) {
                    $new_title = $title . '-Copy';
                    $counter   = 1;

                    while ( post_exists( $new_title ) ) {
                        $new_title = $title . '-Copy-' . $counter;
                        $counter++;
                    }

                    $item['post']['post_title'] = $new_title;
                }

                $post_update = $this->prepare_post_for_import(
                    $item['post'],
                    [
                        'post_type'   => 'fluxtore_flow',
                        'post_parent' => 0,
                    ]
                );
                if ( empty( $post_update ) ) {
                    continue;
                }
                $new_post_id = wp_insert_post( $post_update, true );

                if ( is_wp_error( $new_post_id ) ) {
                    delete_option( $temp_key );
                    wp_send_json_error( $new_post_id->get_error_message() );
                }

                $processed++;
                $regeneration_queue[] = $new_post_id;

                $step_ids       = [];
                $step_map       = [];
                $step_meta_data = [];
                $step_css_data  = [];
                $step_parents   = [];

                if ( ! empty( $item['posts_steps'] ) && is_array( $item['posts_steps'] ) ) {
                    foreach ( $item['posts_steps'] as $index => $post_info ) {
                        if ( empty( $post_info ) ) {
                            continue;
                        }

                        $post_info         = (array) $post_info;
                        $original_step_id  = isset( $post_info['ID'] ) ? absint( $post_info['ID'] ) : 0;
                        $original_parent   = isset( $post_info['post_parent'] ) ? absint( $post_info['post_parent'] ) : 0;

                        if ( ! $original_step_id && isset( $item['steps'][ $index ]['post_id'] ) ) {
                            $original_step_id = absint( $item['steps'][ $index ]['post_id'] );
                        }

                        if ( $original_step_id ) {
                            $step_parents[ $original_step_id ] = $original_parent;
                        }

                        $step_post = $this->prepare_post_for_import(
                            $post_info,
                            [
                                'post_type'   => 'fluxtore_step',
                                'post_parent' => 0,
                            ]
                        );

                        if ( empty( $step_post ) ) {
                            continue;
                        }

                        $step_post_id = wp_insert_post( $step_post, true );

                        if ( is_wp_error( $step_post_id ) ) {
                            delete_option( $temp_key );
                            wp_send_json_error( $step_post_id->get_error_message() );
                        }

                        $step_ids[] = $step_post_id;

                        if ( $original_step_id ) {
                            $step_map[ $original_step_id ] = $step_post_id;
                        }

                        if ( ! empty( $item['steps'][ $index ]['meta'] ) && is_array( $item['steps'][ $index ]['meta'] ) ) {
                            $step_meta_data[ $step_post_id ] = $item['steps'][ $index ]['meta'];
                        } else {
                            $step_meta_data[ $step_post_id ] = [];
                        }

                        if ( ! empty( $item['steps'][ $index ]['elementor_css'] ) && is_array( $item['steps'][ $index ]['elementor_css'] ) ) {
                            $step_css_data[ $step_post_id ] = $item['steps'][ $index ]['elementor_css'];
                        }
                    }
                }

                if ( ! empty( $step_meta_data ) ) {
                    foreach ( $step_meta_data as $step_post_id => $meta_items ) {
                        $has_elementor_data = false;

                        foreach ( $meta_items as $meta_key => $meta_value ) {
                            if ( in_array( $meta_key, [ '_elementor_css', '_elementor_page_assets' ], true ) ) {
                                continue;
                            }

                            $value = $this->normalize_meta_value( $meta_value );

                            if ( '__fluxtore__flow' === $meta_key ) {
                                $value = $new_post_id;
                            } elseif ( in_array( $meta_key, [ '__fluxtore__yes_step', '__fluxtore__no_step' ], true ) ) {
                                $value = $this->map_step_reference( $value, $step_map );
                            } elseif ( '__fluxtore__abtest_variations' === $meta_key ) {
                                $value = $this->map_step_variations( $value, $step_map );
                            } elseif ( '_elementor_data' === $meta_key && ! empty( $value ) ) {
                                $has_elementor_data = true;
                            }

                            update_post_meta( $step_post_id, $meta_key, $value );
                        }

                        update_post_meta( $step_post_id, '__fluxtore__flow', $new_post_id );

                        if ( $has_elementor_data ) {
                            $regeneration_queue[] = $step_post_id;
                        }
                    }
                }

                if ( ! empty( $step_css_data ) ) {
                    foreach ( $step_css_data as $step_post_id => $css_items ) {
                        $this->import_elementor_css_posts( $step_post_id, $css_items );
                    }
                }

                if ( ! empty( $step_parents ) ) {
                    foreach ( $step_parents as $original_id => $original_parent ) {
                        if ( empty( $original_id ) || ! isset( $step_map[ $original_id ] ) ) {
                            continue;
                        }

                        $new_parent_id = 0;

                        if ( $original_parent && isset( $step_map[ $original_parent ] ) ) {
                            $new_parent_id = $step_map[ $original_parent ];
                        }

                        wp_update_post(
                            [
                                'ID'          => $step_map[ $original_id ],
                                'post_parent' => $new_parent_id,
                            ]
                        );
                    }
                }

                update_post_meta( $new_post_id, '__fluxtore__steps', $step_ids );

                if ( ! empty( $item['visitors'] ) ) {
                    update_post_meta( $new_post_id, '__fluxtore__visitors', $item['visitors'] );
                }
            }

            if ( ! empty( $regeneration_queue ) ) {
                do_action( 'fluxtore/after_import_funnel', array_values( array_unique( array_map( 'absint', $regeneration_queue ) ) ) );
            }

            delete_option( $temp_key );

            wp_send_json_success(
                [
                    'message'  => __( 'Funnel imported successfully.', 'fluxtore' ),
                    'imported' => $processed,
                    'total'    => $total,
                    'varify'   => 1,
                ]
            );
        }

        private function prepare_post_for_import( $post_data, array $overrides = [] ) {
            if ( empty( $post_data ) ) {
                return [];
            }

            if ( is_object( $post_data ) ) {
                $post_data = get_object_vars( $post_data );
            }

            if ( ! is_array( $post_data ) ) {
                return [];
            }

            $sanitized        = $post_data;
            $fields_to_unset  = [ 'ID', 'guid', 'filter', 'post_name', 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt', 'comment_count', 'post_parent' ];

            foreach ( $fields_to_unset as $field ) {
                if ( isset( $sanitized[ $field ] ) ) {
                    unset( $sanitized[ $field ] );
                }
            }

            if ( empty( $sanitized['post_author'] ) ) {
                $sanitized['post_author'] = get_current_user_id();
            }

            foreach ( $overrides as $key => $value ) {
                $sanitized[ $key ] = $value;
            }

            if ( empty( $sanitized['post_status'] ) ) {
                $sanitized['post_status'] = 'publish';
            }

            return $sanitized;
        }

        private function normalize_meta_value( $meta_value ) {
            if ( is_array( $meta_value ) && 1 === count( $meta_value ) ) {
                return maybe_unserialize( $meta_value[0] );
            }

            return $meta_value;
        }

        private function map_step_reference( $value, array $step_map ) {
            if ( is_array( $value ) ) {
                $value = reset( $value );
            }

            $reference = absint( $value );

            if ( $reference && isset( $step_map[ $reference ] ) ) {
                return $step_map[ $reference ];
            }

            return 0;
        }

        private function map_step_variations( $value, array $step_map ) {
            if ( empty( $value ) ) {
                return [];
            }

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

            $mapped = [];

            foreach ( $value as $variation ) {
                if ( is_array( $variation ) ) {
                    foreach ( $variation as $single_variation ) {
                        $mapped_value = $this->map_step_reference( $single_variation, $step_map );

                        if ( $mapped_value ) {
                            $mapped[] = $mapped_value;
                        }
                    }

                    continue;
                }

                $mapped_value = $this->map_step_reference( $variation, $step_map );

                if ( $mapped_value ) {
                    $mapped[] = $mapped_value;
                }
            }

            return array_values( array_unique( $mapped ) );
        }

        private function import_elementor_css_posts( $step_post_id, array $css_items ) {
            if ( empty( $step_post_id ) || empty( $css_items ) ) {
                return;
            }

            $existing_css_posts = get_posts(
                [
                    'post_type'   => 'elementor_css',
                    'post_parent' => $step_post_id,
                    'post_status' => 'any',
                    'numberposts' => -1,
                    'fields'      => 'ids',
                ]
            );

            if ( ! empty( $existing_css_posts ) ) {
                foreach ( $existing_css_posts as $existing_id ) {
                    wp_delete_post( $existing_id, true );
                }
            }

            $updated = false;

            foreach ( $css_items as $css_item ) {
                if ( empty( $css_item['post'] ) ) {
                    continue;
                }

                $css_post = $this->prepare_post_for_import(
                    $css_item['post'],
                    [
                        'post_type'   => 'elementor_css',
                        'post_parent' => $step_post_id,
                    ]
                );

                if ( empty( $css_post ) ) {
                    continue;
                }

                $css_post_id = wp_insert_post( $css_post, true );

                if ( is_wp_error( $css_post_id ) ) {
                    continue;
                }

                $updated = true;

                if ( ! empty( $css_item['meta'] ) && is_array( $css_item['meta'] ) ) {
                    foreach ( $css_item['meta'] as $meta_key => $meta_value ) {
                        $value = $this->normalize_meta_value( $meta_value );

                        if ( '_elementor_source' === $meta_key ) {
                            $value = $step_post_id;
                        }

                        update_post_meta( $css_post_id, $meta_key, $value );
                    }
                }
            }

            if ( $updated ) {
                $this->maybe_clear_elementor_css_cache( $step_post_id );
            }
        }

        private function maybe_clear_elementor_css_cache( $step_post_id ) {
            if ( ! class_exists( '\\Elementor\\Plugin' ) ) {
                return;
            }

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

            if ( ! $plugin_instance ) {
                return;
            }

            $files_manager = isset( $plugin_instance->files_manager ) ? $plugin_instance->files_manager : null;

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

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

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

            $css_file = null;

            if ( method_exists( $css_post_class, 'create' ) ) {
                $css_file = $css_post_class::create( $step_post_id );
            }

            if ( ! $css_file ) {
                $css_file = new $css_post_class( $step_post_id );
            }

            if ( $css_file && method_exists( $css_file, 'set_post_id' ) && method_exists( $css_file, 'get_post_id' ) && 0 === (int) $css_file->get_post_id() ) {
                $css_file->set_post_id( $step_post_id );
            }

            if ( $css_file && method_exists( $css_file, 'delete' ) ) {
                $css_file->delete();
            }

            if ( $css_file && method_exists( $css_file, 'update' ) ) {
                $css_file->update();
            } elseif ( $css_file && method_exists( $css_file, 'enqueue' ) ) {
                $css_file->enqueue();
            }
        }
    }
}

fluXtore_Ajax_Funnels::init();
