<?php 

    // prevent direct file access
	if( !defined( 'ABSPATH' ) ) exit;
    
    // require necessary function
    function pixe_block_table_init(){
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');

        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();

        // block table
        $sql = "CREATE TABLE {$wpdb->prefix}pixeblock (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            pixe_type ENUM('block', 'page'),
            author bigint(20) UNSIGNED DEFAULT NULL,
            date_utc datetime DEFAULT NULL,
            title text DEFAULT NULL,
            content longtext,
            content_type ENUM('wrapper', 'column', 'item'),
            PRIMARY KEY (id)
        ) {$charset_collate};";
        dbDelta($sql);
    }

    // get object cache key
    function pixe_block_get_cache_key($args){
        $key = 'pixeblock.v' . pixe_get_cache_version('block');

        if( !empty($args['id']) ){
            $key .= '|' . absint($args['id']);
        }
        if( !empty($args['ids']) && is_array($args['ids']) ){
            sort($args['ids']);
            $key .= '|' . implode(',', $args['ids']);
        }
        if( !empty($args['type']) ){
            $key .= '|' . trim($args['type']);
        }
        if( !empty($args['order']) ){
            $key .= '|' . trim($args['order']);
        }

        return $key;
    }

    // use to insert new data
    function pixe_set_block_data($data){
        global $wpdb;

        $id = '';
        if( !empty($data['id']) ){
            $id = $data['id'];
            unset($data['id']);
        }

        // create data format
        $formats = array();
        foreach( $data as $slug => $value ){

            // prepare json data
            if( is_array($value) ){
                $data[$slug] = json_encode($value);
            }
            
            // set format
            if( $slug == 'author' ){
                $formats[] = '%d';
            }else{
                $formats[] = '%s';
            }
        }

        // insert data
        if( !empty($id) ){
            $wpdb->update("{$wpdb->prefix}pixeblock", $data, array('id' => $id), $formats, array('%d')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache automatically invalidated on data changes
        }else{
            $wpdb->insert("{$wpdb->prefix}pixeblock", $data, $formats); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        }

        // delete cache after update
        pixe_increase_cache_version('block');

        return $wpdb->insert_id;
    }

    // favourite blocks
    add_action('wp_ajax_pixe_save_favourite_block', 'pixe_ajax_save_favourite_block');
    function pixe_ajax_save_favourite_block(){
        
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('manage_options') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // data
        if( !empty($_POST['ids']) ){
            $post_ids = map_deep(wp_unslash($_POST['ids']), 'absint');
        }
        
        if( empty($post_ids) ){
            delete_option('pixe_favourite_blocks');
        }else{
            update_option('pixe_favourite_blocks', $post_ids, false);
        }
    }
    function pixe_get_favourite_block(){
        return get_option('pixe_favourite_blocks', array());
    }

    // set title
    add_action('wp_ajax_pixe_save_block', 'pixe_ajax_save_block');
    function pixe_ajax_save_block(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('manage_options') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }
        
        if( empty($_POST['type']) || empty($_POST['title']) || empty($_POST['content']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $currentuser = wp_get_current_user();
        $currenttime = current_time('mysql', true);

        $content = wp_unslash($_POST['content']); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized below using array_walk_recursive
        if( !is_array($content) ) { $content = array(); }
        array_walk_recursive($content, 'pixe_sanitize_builder_data');

        $templateId = pixe_set_block_data(array(
            'author' => $currentuser->ID,
            'date_utc' => $currenttime,
            'pixe_type' => sanitize_text_field(wp_unslash($_POST['type'])),
            'title' => sanitize_text_field(wp_unslash($_POST['title'])),
            'content' => $content,
            'content_type' => empty($_POST['content-type'])? '': sanitize_text_field(wp_unslash($_POST['content-type']))
        ));

        $ret = array(
            'status' => 'success',
            'template-id' => $templateId
        );
        
        die(json_encode($ret));
    }

    // ajax get template
    add_action('wp_ajax_pixe_get_block', 'pixe_ajax_get_block');
    function pixe_ajax_get_block(){
        
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }
        
        // check data
        if( empty($_POST['id']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $result = pixe_get_block(absint(wp_unslash($_POST['id'])));

        if( empty($result) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('Block Not Found', 'pixebuilder'),
                'message'=> esc_html__('Cannot find the block you\'re selected.' ,'pixebuilder')
            )));
        }else{
            die(json_encode(array(
                'status' => 'success',
                'type' => $result->pixe_type,
                'content' => json_decode($result->content, true)
            )));
        }
        
    }

    // query template
    function pixe_get_block_list($type){
        $ret = array();
        
        $templates = pixe_get_blocks($type);
        foreach( $templates as $template ){
            $t = array(
                'id' => $template->id,
                'title' => $template->title,
                'content-type' => $template->content_type
            );
            $ret[] = $t;
        }

        return $ret;
    }

    // query all ids
    function pixe_get_blocks($type){
        global $wpdb;

        // get result from cache first
        $cache_key = pixe_block_get_cache_key(array('type' => $type, 'order' => 'id,desc'));
        $results = wp_cache_get($cache_key, 'pixebuilder');
        if( !empty($results) ) return $results;
        
        // no cache, query from database
        $results = $wpdb->get_results($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
            "SELECT * FROM {$wpdb->prefix}pixeblock WHERE pixe_type = %s ORDER BY id DESC;", $type 
        ));
        wp_cache_set($cache_key, $results, 'pixebuilder', DAY_IN_SECONDS);

        return $results;
    }

    function pixe_get_block($id){
        if( empty($id) ) return array();

        global $wpdb;

        // query all ids
        $sql  = "SELECT * FROM {$wpdb->prefix}pixeblock ";
        if( is_array($id) ){

            $ids = array_unique(array_map('absint', $id));
            if( empty($ids) ) return array();

            // get result from cache first
            $cache_key = pixe_block_get_cache_key(array('ids' => $ids));
            $result = wp_cache_get($cache_key, 'pixebuilder');
            if( !empty($result) ) return $result;

            // no cache, query from database
            $placeholder = implode(',', array_fill(0, count($ids), '%d'));
            $result = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}pixeblock WHERE id IN({$placeholder})", $ids)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Dynamic placeholder list generated safely
            wp_cache_set($cache_key, $result, 'pixebuilder', DAY_IN_SECONDS);
        }else{

            // get result from cache first
            $cache_key = pixe_block_get_cache_key(array('id' => $id));
            $result = wp_cache_get($cache_key, 'pixebuilder');
            if( !empty($result) ) return $result;

            // no cache, query from database
            $result = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}pixeblock WHERE id = %d ", $id)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
            wp_cache_set($cache_key, $result, 'pixebuilder', DAY_IN_SECONDS);
        }
        
        return $result;
    }

    // import block
    add_action('wp_ajax_pixe_import_blocks', 'pixe_ajax_import_blocks');
    function pixe_ajax_import_blocks(){
        
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('manage_options') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['file']['id']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $file = get_attached_file(absint(wp_unslash($_POST['file']['id'])));

        if( !file_exists($file) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('File Not Found', 'pixebuilder'),
                'message'=> esc_html__('Please refresh the page and try again.' ,'pixebuilder')
            )));
        }

        $json_data = file_get_contents($file);
        $data = json_decode($json_data, true);
        
        // import each block
        $new_blocks = array();
        foreach($data as $block){

            if( !empty($block['pixe_type']) && !empty($block['title']) && !empty($block['content']) && !empty($block['content_type']) ){
                $currentuser = wp_get_current_user();
                $currenttime = current_time('mysql', true);

                $block_id = pixe_set_block_data(array(
                    'author' => $currentuser->ID,
                    'date_utc' => $currenttime,
                    'pixe_type' => $block['pixe_type'],
                    'title' => $block['title'],
                    'content' => $block['content'],
                    'content_type' => $block['content_type']
                ));

                $new_blocks[] = array(
                    'pixe_type' => $block['pixe_type'],
                    'id' => $block_id,
                    'title' => $block['title'],
                    'content-type' => $block['content_type']
                );
            }
        }

        die(json_encode(array(
            'status' => 'success',
            'blocks' => $new_blocks
        )));

    }

    // export block
    add_action('wp_ajax_pixe_export_blocks', 'pixe_ajax_export_blocks');
    function pixe_ajax_export_blocks(){
        
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check data
        if( empty($_POST['ids']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $ids = array_unique(array_map('absint', wp_unslash($_POST['ids']))); 
        $data = pixe_get_block($ids);

        if( empty($data) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('No Blocks Found', 'pixebuilder'),
                'message'=> esc_html__('Please refresh the page and try again.' ,'pixebuilder')
            )));
        }
        
        die(json_encode(array(
            'status' => 'success',
            'data' => $data
        )));
    }

    // remove block
    add_action('wp_ajax_pixe_remove_block', 'pixe_ajax_remove_block');
    function pixe_ajax_remove_block(){
        
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('manage_options') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['id']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        global $wpdb;
        $id = absint(wp_unslash($_POST['id']));
        $wpdb->delete("{$wpdb->prefix}pixeblock", array('id' => $id), array('%d')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache automatically invalidated on data changes
        
        // delete cache after update
        pixe_increase_cache_version('block');

        die(json_encode(array( 'status' => 'success' )));
    }

    // set title
    add_action('wp_ajax_pixe_set_block_title', 'pixe_ajax_set_block_title');
    function pixe_ajax_set_block_title(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('manage_options') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['id']) || empty($_POST['title']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        pixe_set_block_data(array(
            'id' => absint(wp_unslash($_POST['id'])),
            'title' => sanitize_text_field(wp_unslash($_POST['title']))
        ));
        
        die(json_encode(array(
            'status' => 'success',
        )));
    }