<?php

namespace GS_BOOKS;

/**
 * Protect direct access
 */
if (!defined('ABSPATH')) exit;

class Import_Export {

    private $zip_instance;
    private $zip_file;
    private $upload_dir;

    public function __construct() {
        add_action('wp_ajax_gs_books_export_data', array($this, 'gs_books_export_data'));
        add_action('wp_ajax_gs_books_import_data', array($this, 'gs_books_import_data'));
        add_action('admin_menu', array($this, 'register_sub_menu'), 40);
        // add_action('init', array($this, 'delete__books_data'), 40);
    }

    public function gs_books_export_data() {

        // Check for valid nonce
        check_ajax_referer('_gs_books_admin_nonce_gs_');

        // Check for valid user permissions
        if (!current_user_can('manage_options')) wp_send_json_error(__('You do not have permission to perform this action', 'gs-books-showcase'), 403);

        // Check for required data
        if (empty($export_data = $_REQUEST['export_data'])) wp_send_json_error(__('No export data provided', 'gs-books-showcase'), 400);

        // Validate the export data
        $export_books = wp_validate_boolean($export_data['books']);
        $export_shortcodes = wp_validate_boolean($export_data['shortcodes']);
        $export_settings = wp_validate_boolean($export_data['settings']);

        // Check for valid export data
        if (!$export_books && !$export_shortcodes && !$export_settings) wp_send_json_error(__('No export data provided', 'gs-books-showcase'), 400);

        // Init the zip archive
        $this->init_zip_file();

        // Init the JSON data
        $json_data = [];

        // Add Posts Data to the zip file
        if ($export_books) $json_data = $this->export__books($json_data);

        // Add Shortcodes Data to the zip file
        if ($export_shortcodes) $json_data = $this->export__shortcodes($json_data);

        // Add Settings Data to the zip file
        if ($export_settings) $json_data = $this->export__settings($json_data);

        // Add the JSON data to the zip file
        $this->zip_instance->addFromString('data.json', json_encode($json_data, JSON_PRETTY_PRINT));

        // Send the zip file
        $this->send_zip_file_data();
    }

    function delete_directory( $dir ) {
        $wp_filesystem = get_wp_filesystem();
        if ( ! $wp_filesystem ) {
            return false; // Filesystem not available
        }

        if ( ! $wp_filesystem->exists( $dir ) ) {
            return false;
        }

        if ( ! $wp_filesystem->is_dir( $dir ) ) {
            return wp_delete_file( $dir );
        }

        foreach ( $wp_filesystem->dirlist( $dir ) as $item => $details ) {
            $path = trailingslashit( $dir ) . $item;

            if ( 'd' === $details['type'] ) {
                if ( ! $this->delete_directory( $path ) ) {
                    return false;
                }
            } else {
                if ( ! $wp_filesystem->delete( $path ) ) {
                    return false;
                }
            }
        }

        return $wp_filesystem->rmdir( $dir );
    }

    public function save_imported_file() {
        // Security check: verify nonce if you have one
        if ( ! isset( $_FILES['import_file'] ) ) {
            wp_send_json_error( __( 'No file uploaded', 'gs-books-showcase' ), 400 );
        }

        $import_file = $_FILES['import_file'];

        // Allowed mime types
        $allowed_mimes = array( 'application/zip' => 'zip' );

        // Use WordPress upload handler
        require_once ABSPATH . 'wp-admin/includes/file.php';

        $uploaded = wp_handle_upload( $import_file, array(
            'test_form' => false,
            'mimes'     => $allowed_mimes,
        ) );

        if ( isset( $uploaded['error'] ) ) {
            wp_send_json_error( $uploaded['error'], 400 );
        }

        $dest_file_path = $uploaded['file'];
        $upload_file_dir = dirname( $dest_file_path );

        // Ensure target directory
        if ( is_dir( $upload_file_dir ) ) {
            $this->delete_directory( $upload_file_dir );
        }
        wp_mkdir_p( $upload_file_dir );

        // Unzip
        $zip = new \ZipArchive;
        if ( $zip->open( $dest_file_path ) === true ) {
            $zip->extractTo( $upload_file_dir );
            $zip->close();

            // Remove uploaded zip after extraction
            wp_delete_file( $dest_file_path );
        } else {
            wp_send_json_error( __( 'File extraction failed', 'gs-books-showcase' ), 400 );
        }

        return $upload_file_dir;
    }

    public function gs_books_import_data() {

        // Check for valid nonce
        check_ajax_referer('_gs_books_admin_nonce_gs_');

        // Check for valid user permissions
        if (!current_user_can('manage_options')) wp_send_json_error(__('You do not have permission to perform this action', 'gs-books-showcase'), 403);

        // Check for required data
        if (empty($_FILES['import_file'])) wp_send_json_error(__('No import file provided', 'gs-books-showcase'), 400);

        // Save the uploaded file
        $this->upload_dir = $this->save_imported_file();

        // Check if the data.json file exists
        $json_import_file = $this->upload_dir . '/data.json';
        if ( !file_exists($json_import_file) ) wp_send_json_error(__('Invalid file', 'gs-books-showcase'), 400);

        // Read the JSON data
        $json_data = @file_get_contents($this->upload_dir . '/data.json');
        $json_data = json_decode($json_data, true);

        // Check for valid JSON data
        if (empty($json_data)) wp_send_json_error(__('Invalid file content', 'gs-books-showcase'), 400);
        
        // Initiate the Import Process
        $this->import__books_data( $json_data );

        // Delete the uploaded files
        $this->delete_directory($this->upload_dir);

        // Send the success message
        wp_send_json_success(__('Data imported successfully', 'gs-books-showcase'), 200 );
    }

    public function import__books_data( $json_data ) {

        // Import the Settings Data
        if (!empty($json_data['settings'])) {
            plugin()->builder->_save_shortcode_pref($json_data['settings'], false);
        }

        // Import the Localization Data
        if (!empty($json_data['localization'])) {
            plugin()->builder->_save_shortcode_pref($json_data['localization'], false);
        }

        // Import the Settings Data
        if (!empty($json_data['taxonomy_settings'])) {
            plugin()->builder->_save_taxonomy_settings($json_data['taxonomy_settings'], false);
        }

        // Import the Attachments Data
        if (!empty($json_data['attachments'])) {
            $this->import__attachments($json_data['attachments']);
        }

        // Import the Terms Data
        if (!empty($json_data['terms'])) {
            plugin()->cpt->register_taxonomies();
            $this->import__terms($json_data['terms']);
        }

        // Import the Posts Data
        if (!empty($json_data['posts'])) {
            $this->import__posts($json_data['posts']);
        }

        // Import the Shortcodes Data
        if (!empty($json_data['shortcodes'])) {
            $this->import__shortcodes($json_data['shortcodes']);
        }

    }

    // Test Purpose
    public function delete__books_data() {

        // Delete All the Posts
        $posts = get_posts([
            'posts_per_page'    => -1,
            'post_type'         => 'gs_bookshowcase',
        ]);
        foreach ($posts as $post) {
            wp_delete_post($post->ID, true);
        }

        // Delete All the Attachments where post_type is 'attachment' && meta_key is '_gs_book_import_id'
        $attachments = get_posts([
            'posts_per_page'    => -1,
            'post_type'         => 'attachment',
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
            'meta_key'          => '_gs_book_import_id'
        ]);
        foreach ($attachments as $attachment) {
            wp_delete_post($attachment->ID, true);
        }

        // Delete All the Terms
        foreach ($this->get_taxonomy_list() as $taxonomy) {

            if ( ! taxonomy_exists($taxonomy) ) continue;

            $terms = get_terms([
                'taxonomy' => $taxonomy,
                'hide_empty' => false
            ]);

            // check in $terms are invalid
            if (is_wp_error($terms)) continue;

            foreach ($terms as $term) {
                wp_delete_term($term->term_id, $taxonomy);
            }
        }

        // Delete All the Shortcodes
        global $wpdb;
         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->query("DELETE FROM {$wpdb->prefix}gs_books");
    }

    public function import__terms($terms) {

        foreach ($terms as $term) {

            $term_data = array(
                'slug' => $term['slug'],
                'description' => $term['description'],
                'parent' => $term['parent']
            );

            if ( ! taxonomy_exists( $term['taxonomy'] ) ) continue;

            $inserted_term = wp_insert_term($term['name'], $term['taxonomy'], $term_data);
            
            if (is_wp_error($inserted_term)) continue;

            add_term_meta($inserted_term['term_id'], '_gs_book_import_id', $term['term_id']);

        }

    }

    public function import__attachments($attachments) {

        require_once(ABSPATH . 'wp-admin/includes/image.php');

        wp_raise_memory_limit('image');

        foreach ($attachments as $attachment) {

            $file = $this->upload_dir . '/attachments/' . $attachment['file_name'];

            if (!file_exists($file)) continue;

            $mirror = wp_upload_bits(basename($file), null, file_get_contents($file));

            if (!empty($mirror['error'])) continue;

            $attachment_data = array(
                'guid'           => $mirror['url'],
                'post_mime_type' => $mirror['type'],
                'post_title'     => $attachment['title'],
                'post_content'   => $attachment['description'],
                'post_status'    => 'inherit',
                'post_excerpt'   => $attachment['caption'],
                'meta_input'     => array(
                    '_wp_attachment_image_alt' => $attachment['alt_text'],
                    '_gs_book_import_id' => $attachment['ID']
                )
            );

            $attachment_id = wp_insert_attachment($attachment_data, $mirror['file']);

            if (is_wp_error($attachment_id)) continue;

            $attach_data = wp_generate_attachment_metadata($attachment_id, $mirror['file']);

            wp_update_attachment_metadata($attachment_id, $attach_data);

        }

    }

    public function import__posts($posts) {

        foreach ($posts as $post) {

            $meta_input = $post['meta_input'];

            $meta_input = array_map(function($value) {
                if ( !empty($value) ) {
                    if ( is_array($value) ) {
                        return $value[0];
                    } else {
                        return $value;
                    }
                }
                return '';
            }, $meta_input);

            $meta_input['_gs_book_import_id'] = $post['ID'];

            unset($post['ID']);

            if ( isset( $meta_input['_thumbnail_id'] ) ) {
                $thumbnail_id = $this->get_imported_post_id( $meta_input['_thumbnail_id'] );
                if ($thumbnail_id) {
                    $meta_input['_thumbnail_id'] = $thumbnail_id;
                } else {
                    unset($meta_input['_thumbnail_id']);
                }
            }

            if ( !empty( $meta_input['gsb_gallery'] ) ) {
                $gallery_ids = explode(',', $meta_input['gsb_gallery']);
                foreach ($gallery_ids as $key => $gallery_id) {
                    $gallery_ids[$key] = $this->get_imported_post_id( (int) $gallery_id );
                }
                if ( !empty( $gallery_ids ) ) {
                    $meta_input['gsb_gallery'] = implode(',', $gallery_ids);
                } else {
                    unset($meta_input['gsb_gallery']);
                }
            }

            $post['meta_input'] = $meta_input;

            foreach ($post['tax_input'] as $taxonomy => $terms) {
                
                if ( ! taxonomy_exists( $taxonomy ) ) {
                    unset($post['tax_input'][$taxonomy]);
                    continue;
                }

                foreach ($terms as $key => $term) {
                    $term_id = (int) $this->get_imported_term_id($term);
                    if ($term_id) {
                        $terms[$key] = $term_id;
                    } else {
                        unset($terms[$key]);
                    }
                }

                $post['tax_input'][$taxonomy] = $terms;

            }

            wp_insert_post($post);
        }
        
    }

    public function replace_with_imported_terms($terms) {

        if (empty($terms)) return [];

        $terms = array_map(function($term) {
            $term_id = $this->get_imported_term_id( (int) $term);
            return $term_id ? $term_id : '';
        }, $terms);

        return array_filter($terms);
    }

    public function import__shortcodes($shortcodes) {

        global $wpdb;

        $builder = plugin()->builder;

        foreach ($shortcodes as $shortcode) {

            // Validate the shortcode settings
            $shortcode_settings = json_decode($shortcode['shortcode_settings'], true);
            $shortcode_settings = $builder->validate_shortcode_settings($shortcode_settings);

            // Replace the old term IDs with the new term IDs
            $shortcode_settings['group']         = $this->replace_with_imported_terms( $shortcode_settings['group'] );
            $shortcode_settings['exclude_group'] = $this->replace_with_imported_terms( $shortcode_settings['exclude_group'] );
            $shortcode_settings['include_tags']  = $this->replace_with_imported_terms( $shortcode_settings['include_tags'] );
            $shortcode_settings['exclude_tags']  = $this->replace_with_imported_terms( $shortcode_settings['exclude_tags'] );

            // Set the new shortcode settings
            $shortcode['shortcode_settings'] = json_encode($shortcode_settings);
            
            // Unset the ID
            unset($shortcode['id']);

            // Insert the shortcode
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
            $wpdb->insert($wpdb->prefix . 'gs_books', $shortcode, [
                'shortcode_name'     => '%s',
                'shortcode_settings' => '%s',
                'created_at'         => '%s',
                'updated_at'         => '%s',
            ]);

            // Trigger the shortcode created action
            do_action( 'gs_books_shortcode_created', $wpdb->insert_id );
            do_action( 'gsp_shortcode_created', $wpdb->insert_id );
        }

        // Delete the shortcode cache
        wp_cache_delete( 'gs_book_shortcode', 'gs_book_showcase' );

    }

    public function get_imported_post_id($post_id) {

        global $wpdb;

        $post_id = (int) $post_id;

        if (!$post_id) return false;
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $post_id = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_gs_book_import_id' AND meta_value = %d LIMIT 1", $post_id));

        if (!$post_id) return false;

        return $post_id;
    }

    public function get_imported_term_id($term_id) {

        global $wpdb;

        $term_id = (int) $term_id;

        if (!$term_id) return false;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $term_id = $wpdb->get_var($wpdb->prepare("SELECT term_id FROM $wpdb->termmeta WHERE meta_key = '_gs_book_import_id' AND meta_value = %d LIMIT 1", $term_id));

        if (!$term_id) return false;

        return $term_id;
    }

    public function export__books($json_data = []) {

        $json_data['taxonomy_settings'] = plugin()->builder->_get_taxonomy_settings( false );

        $json_data['posts']             = [];
        $json_data['attachments']       = [];
        $json_data['terms']             = [];

        $posts = get_posts([
            'posts_per_page'    => -1,
            'post_type'         => 'gs_bookshowcase',
        ]);

        // Add Posts Data to the zip file
        foreach ($posts as $post) {

            extract((array) $post);

            $post_data = compact("ID", "post_date", "post_date_gmt", "post_content", "post_title", "post_excerpt", "post_status", "comment_status", "ping_status", "post_password", "post_name", "post_modified", "post_modified_gmt", "post_parent", "menu_order", "post_type");

            $post_data['meta_input'] = get_post_meta($ID, '', true);

            foreach ($post_data['meta_input'] as $meta_key => $meta_value) {
                foreach ($meta_value as $key => $value) {
                    if (is_serialized($value)) {
                        $meta_value[$key] = maybe_unserialize($value);
                    }
                }
                $post_data['meta_input'][$meta_key] = $meta_value;
            }

            $post_data['tax_input'] = [];
            foreach ( $this->get_taxonomy_list() as $taxonomy ) {
                $post_data['tax_input'][$taxonomy] = wp_get_post_terms($ID, $taxonomy, ['fields' => 'ids']);
            }

            unset($post_data['meta_input']['_edit_last']);
            unset($post_data['meta_input']['_edit_lock']);
            unset($post_data['meta_input']['gsbooks-demo_data']);

            $json_data['posts'][] = $post_data;
        }

        // Generate Attachments Data
        foreach ($posts as $post) {

            $thumbnail_id = get_post_thumbnail_id($post->ID);
            $gallery_ids = get_post_meta($post->ID, 'gsb_gallery', true);

            if ($thumbnail_id) {
                $thumbnail_data = $this->get_attachment_export_data($thumbnail_id);
                if ( !empty($thumbnail_data) ) {
                    $json_data['attachments'][] = $thumbnail_data;
                }
            }

            if ( !empty($gallery_ids) ) {
                $gallery_ids = array_map('intval', explode(',', $gallery_ids));
                foreach ($gallery_ids as $gallery_id) {
                    $gallery_data = $this->get_attachment_export_data($gallery_id);
                    if ( !empty($gallery_data) ) {
                        $json_data['attachments'][] = $gallery_data;
                    }
                }
            }
        }

        // Add Attachments Data to the zip file
        foreach ($json_data['attachments'] as $key => $attachment) {
            $file_name = basename($attachment['file_path']);
            $this->zip_instance->addFile($attachment['file_path'], 'attachments/' . basename($attachment['file_path']));
            $json_data['attachments'][$key]['file_name'] = $file_name;
            unset($json_data['attachments'][$key]['file_path']);
        }

        // Add Terms Data to the zip file
        $json_data['terms'] = get_terms([
            'taxonomy' => $this->get_taxonomy_list(),
            'hide_empty' => false
        ]);

        return $json_data;
    }

    public function export__shortcodes($json_data = []) {

        // Add Shortcodes Data to the zip file
        $json_data['shortcodes'] = $this->get_shortcode_list();

        // Return the generated data
        return $json_data;
    }

    public function export__settings($json_data = []) {

        // Add Shortcodes Data to the zip file
        $json_data['settings'] = plugin()->builder->_get_shortcode_pref( false );
        $json_data['localization'] = plugin()->builder->_get_localization( false );

        // Return the generated data
        return $json_data;
    }

    public function get_attachment_export_data($attachment_id) {
        $attachment = get_post($attachment_id);
        
        if ( empty($attachment) || !is_object($attachment) ) return false;
        if ( $attachment->post_type !== 'attachment' ) return false;
        if ( empty( get_attached_file( $attachment_id ) ) ) return false;

        $attachment_data = array(
            'ID' => $attachment->ID,
            'title' => $attachment->post_title,
            'description' => $attachment->post_content,
            'caption' => $attachment->post_excerpt,
            'alt_text' => get_post_meta($attachment_id, '_wp_attachment_image_alt', true),
            'file_path' => get_attached_file($attachment_id)
        );
        return $attachment_data;
    }

    public function register_sub_menu() {

        $builder = plugin()->builder;

        add_submenu_page(
            'edit.php?post_type=gs_bookshowcase',
            'Import & Export',
            'Import & Export',
            'publish_pages',
            'gs-books-shortcode#/import-export',
            array($builder, 'view')
        );
    }

    public function get_taxonomy_list() {

        $taxonomies = ['bookshowcase_group', 'gsb_tag', 'gsb_author', 'gsb_genre', 'gsb_series', 'gsb_languages', 'gsb_publishers', 'gsb_countries'];

        return array_filter( $taxonomies, 'taxonomy_exists' );
    }

    public function get_shortcode_list() {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $shortcodes = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}gs_books", ARRAY_A);
        if (empty($shortcodes)) return [];

        $builder = plugin()->builder;

        foreach ($shortcodes as $shortcode) {
            $shortcode["shortcode_settings"] = json_decode($shortcode["shortcode_settings"], true);
            $shortcode["shortcode_settings"] = $builder->validate_shortcode_settings($shortcode["shortcode_settings"]);
        }

        return $shortcodes;
    }

    public function init_zip_file() {

        // Init the zip archive
        $this->zip_instance = new \ZipArchive();

        // Init the zip file
        $this->zip_file = get_temp_dir() . '/gs-plugins/gs-book-plugin--export.zip';

        // Delete the zip file if it exists
        if (file_exists($this->zip_file)) wp_delete_file($this->zip_file);

        // Create the zip file
        wp_mkdir_p(dirname($this->zip_file));

        // Open the zip file
        $this->zip_instance->open($this->zip_file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
    }

    public function send_zip_file_data() {
        // Close the zip file first
        $this->zip_instance->close();

        if ( ! file_exists( $this->zip_file ) ) {
            wp_die( esc_html__( 'File not found.', 'gs-books-showcase' ), 404 );
        }

        // Get WP_Filesystem instance
        $wp_filesystem = get_wp_filesystem();
        if ( ! $wp_filesystem ) {
            wp_die( esc_html__( 'Filesystem error.', 'gs-books-showcase' ), 500 );
        }

        // Read file contents safely
        $file_contents = $wp_filesystem->get_contents( $this->zip_file );
        if ( false === $file_contents ) {
            wp_die( esc_html__( 'Unable to read export file.', 'gs-books-showcase' ), 500 );
        }

        // Send headers
        nocache_headers();
        header( 'Content-Description: File Transfer' );
        header( 'Content-Type: application/zip' );
        header( 'Content-Disposition: attachment; filename="export.zip"' );
        header( 'Content-Length: ' . strlen( $file_contents ) );

        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo $file_contents;

        // Cleanup
        wp_delete_file( $this->zip_file );
        exit;
    }
}