<?php
/*
 * Do Not USE namespace because The Pro Add-On Used this Class
 */

use NinjaTable\TableDrivers\NinjaFooTable;
use NinjaTables\Classes\ArrayHelper;

/**
 * The admin-specific functionality of the plugin.
 *
 * @link       https://wpmanageninja.com
 * @since      1.0.0
 *
 * @package    ninja-tables
 * @subpackage ninja-tables/admin
 */
class NinjaTablesAdmin
{
    /**
     * The ID of this plugin.
     *
     * @since    1.0.0
     * @access   private
     * @var      string $plugin_name The ID of this plugin.
     */
    private $plugin_name;

    /**
     * Custom Post Type Name
     *
     * @since    1.0.0
     * @access   private
     * @var      string $cpt_name .
     */
    private $cpt_name;

    /**
     * The version of this plugin.
     *
     * @since    1.0.0
     * @access   private
     * @var      string $version The current version of this plugin.
     */
    private $version;

    /**
     * Initialize the class and set its properties.
     *
     * @param string $plugin_name The name of this plugin.
     * @param string $version The version of this plugin.
     * @since    1.0.0
     *
     */
    public function __construct($plugin_name = 'ninja-tables', $version = NINJA_TABLES_VERSION)
    {
        $this->plugin_name = $plugin_name;
        $this->version = $version;
        $this->cpt_name = 'ninja-table';

        add_action('admin_enqueue_scripts', array($this, 'enqueue_data_tables_scripts'));

    }

    /**
     * Register form post types
     *
     * @return void
     */
    public function register_post_type()
    {
        $args = array(
            'label'               => __('Ninja Tables', 'ninja-tables'),
            'public'              => false,
            'publicly_queryable'  => false,
            'exclude_from_search' => true,
            'show_ui'             => true,
            'show_in_menu'        => false,
            'capability_type'     => 'post',
            'hierarchical'        => false,
            'query_var'           => false,
            'supports'            => array('title'),
            'labels'              => array(
                'name'               => __('Ninja Tables', 'ninja-tables'),
                'singular_name'      => __('Table', 'ninja-tables'),
                'menu_name'          => __('Ninja Tables', 'ninja-tables'),
                'add_new'            => __('Add Table', 'ninja-tables'),
                'add_new_item'       => __('Add New Table', 'ninja-tables'),
                'edit'               => __('Edit', 'ninja-tables'),
                'edit_item'          => __('Edit Table', 'ninja-tables'),
                'new_item'           => __('New Table', 'ninja-tables'),
                'view'               => __('View Table', 'ninja-tables'),
                'view_item'          => __('View Table', 'ninja-tables'),
                'search_items'       => __('Search Table', 'ninja-tables'),
                'not_found'          => __('No Table Found', 'ninja-tables'),
                'not_found_in_trash' => __('No Table Found in Trash', 'ninja-tables'),
                'parent'             => __('Parent Table', 'ninja-tables'),
            ),
        );
        $args = apply_filters('ninja_table_post_type_args', $args);
        register_post_type($this->cpt_name, $args);
    }


    /**
     * Adds a settings page link to a menu
     *
     * @link  https://codex.wordpress.org/Administration_Menus
     * @since 1.0.0
     * @return void
     */
    public function add_menu()
    {
        global $submenu;
        $capability = ninja_table_admin_role();

        // Continue only if the current user has
        // the capability to manage ninja tables
        if (!$capability) {
            return;
        }

        // Top-level page
        $menuName = __('Ninja Tables', 'ninja-tables');
        if (defined('NINJATABLESPRO')) {
            $menuName .= ' Pro';
        }

        add_menu_page(
            $menuName,
            $menuName,
            $capability,
            'ninja_tables',
            array($this, 'main_page'),
            ninja_table_get_icon_url(),
            25
        );

        $submenu['ninja_tables']['all_tables'] = array(
            __('Tables', 'ninja-tables'),
            $capability,
            'admin.php?page=ninja_tables#/home',
            '',
            'ninja_tables_all_tables'
        );

        $submenu['ninja_tables']['import'] = array(
            __('Import', 'ninja-tables'),
            $capability,
            'admin.php?page=ninja_tables#/tools',
            '',
            'ninja_table_import_menu'
        );

        $submenu['ninja_tables']['tools'] = array(
            __('Tools', 'ninja-tables'),
            $capability,
            'admin.php?page=ninja_tables#/tools',
            '',
            'ninja_table_tools_menu'
        );

        if (!defined('NINJA_CHARTS_VERSION')) {
            $submenu['ninja_tables']['ninja_charts'] = array(
                __('Charts', 'ninja-tables'),
                $capability,
                'admin.php?page=ninja_tables#/charts'
            );
        } else {
            $submenu['ninja_tables']['ninja_charts'] = array(
                __('Charts', 'ninja-tables'),
                $capability,
                'admin.php?page=ninja-charts#/chart-list'
            );

            $submenu['ninja_tables']['add_chart'] = array(
                __('Add Chart', 'ninja-tables'),
                $capability,
                'admin.php?page=ninja-charts#/add-chart',
            );
        }

        if (!defined('NINJATABLESPRO')) {
            $submenu['ninja_tables']['upgrade_pro'] = array(
                __('<span style="color:#f39c12;">Get Pro</span>', 'ninja-tables'),
                $capability,
                'https://wpmanageninja.com/downloads/ninja-tables-pro-add-on/?utm_source=ninja-tables&utm_medium=wp&utm_campaign=wp_plugin&utm_term=upgrade_menu',
                '',
                'ninja_table_upgrade_menu'
            );
        } else if (defined('NINJATABLESPRO_SORTABLE')) {
            $license = get_option('_ninjatables_pro_license_status');
            if ($license != 'valid' && is_multisite()) {
                $license = get_network_option(get_main_network_id(), '_ninjatables_pro_license_status');
            }

            if ($license != 'valid') {
                $text = 'Activate License';
                if ($license == 'expired') {
                    $text = 'Renew License';
                }

                $submenu['ninja_tables']['activate_license'] = array(
                    '<span style="color:#f39c12;">' . $text . '</span>',
                    $capability,
                    'admin.php?page=ninja_tables#/tools/licensing',
                    '',
                    'ninja_table_license_menu'
                );


            }
        }

        ninjaTablesAdminPrintStyles();

        $submenu['ninja_tables']['help'] = array(
            __('Help', 'ninja-tables'),
            $capability,
            'admin.php?page=ninja_tables#/help',
            '',
            'ninja_tables_help'
        );
    }

    public function main_page()
    {
        include(plugin_dir_path(__FILE__) . 'partials/wp_data_tables_display.php');
    }

    /**
     * Register the stylesheets for the admin area.
     *
     * @since    1.0.0
     */
    public function enqueue_styles()
    {
        $vendorSrc = plugin_dir_url(__DIR__) . "assets/css/ninja-tables-vendor.css";

        if (is_rtl()) {
            $vendorSrc = plugin_dir_url(__DIR__) . "assets/css/ninja-tables-vendor-rtl.css";
        }

        wp_enqueue_style(
            $this->plugin_name . '-vendor',
            $vendorSrc,
            [],
            $this->version,
            'all'
        );

        wp_enqueue_style(
            $this->plugin_name,
            plugin_dir_url(__DIR__) . "assets/css/ninja-tables-admin.css",
            array(),
            $this->version,
            'all'
        );
    }

    /**
     * Register the JavaScript for the admin area.
     *
     * @since    1.0.0
     */
    public function enqueue_scripts()
    {
        if (function_exists('wp_enqueue_editor')) {
            add_filter('user_can_richedit', function ($status) {
                return true;
            });
            wp_enqueue_editor();
            wp_enqueue_script('thickbox');
        }
        if (function_exists('wp_enqueue_media')) {
            wp_enqueue_media();
        }

        wp_enqueue_script(
            'ninja_table_boot',
            plugin_dir_url(__DIR__) . "assets/js/ninja-tables-boot.js",
            array('jquery'),
            $this->version,
            false
        );

        do_action('ninja_tables_loaded_boot_script');

        wp_enqueue_script(
            $this->plugin_name,
            plugin_dir_url(__DIR__) . "assets/js/ninja-tables-admin." . NINJA_TABLES_ASSET_VERSION . ".js",
            array('jquery'),
            $this->version,
            true
        );

        $fluentUrl = admin_url('plugin-install.php?s=FluentForm&tab=search&type=term');

        $isInstalled = defined('FLUENTFORM') || defined('NINJATABLESPRO');
        $dismissed = false;
        $dismissedTime = get_option('_ninja_tables_plugin_suggest_dismiss');

        if ($dismissedTime) {
            if ((time() - intval($dismissedTime)) < 518400) {
                $dismissed = true;
            }
        } else {
            $dismissed = true;
            update_option('_ninja_tables_plugin_suggest_dismiss', time() - 345600);
        }

        $currentUser = wp_get_current_user();

        $leadStatus = false;
        $reviewOptinStatus = false;
        $tableCount = wp_count_posts($this->cpt_name);
        $totalPublishedTable = 0;
        if ($tableCount && $tableCount->publish > 1) {
            $leadStatus = apply_filters('ninja_tables_show_lead', $leadStatus);
        }
        if ($tableCount->publish > 2 && !$leadStatus) {
            $reviewOptinStatus = apply_filters('ninja_tables_show_review_optin', $reviewOptinStatus);
        }

        if ($tableCount && $tableCount->publish > 0) {
            $totalPublishedTable = $tableCount->publish;
        }

        $hasFluentFrom = defined('FLUENTFORM_VERSION');
        $isFluentFromUpdated = false;

        // check for right version
        if ($hasFluentFrom) {
            if ($fluentVersionCompare = version_compare(FLUENTFORM_VERSION, '1.7.4') >= 1) {
                $isFluentFromUpdated = true;
            }
        }

        // Let's deregister existing vuejs by other devs
        // Other devs should not regis
        add_action('admin_print_scripts', function () {
            wp_dequeue_script('vuejs');
            wp_dequeue_script('vue');
        });

        if (current_user_can('manage_options')) {
            $isAdmin = 'yes';
        } else {
            $isAdmin = 'no';
        }


        wp_localize_script($this->plugin_name, 'ninja_table_admin', array(
            'img_url'                  => plugin_dir_url(__DIR__) . "assets/img/",
            'fluentform_url'           => $fluentUrl,
            'fluent_wp_url'            => 'https://wordpress.org/plugins/fluentform/',
            'fluent_form_icon'         => getNinjaFluentFormMenuIcon(),
            'dismissed'                => $dismissed,
            'show_lead_pop_up'         => $leadStatus,
            'show_review_dialog'       => $reviewOptinStatus,
            'current_user_name'        => $currentUser->display_name,
            'isInstalled'              => $isInstalled,
            'hasPro'                   => defined('NINJATABLESPRO'),
            'hasFluentForm'            => $hasFluentFrom,
            'isFluentFormUpdated'      => $isFluentFromUpdated,
            'hasAdvancedFilters'       => class_exists('NinjaTablesPro\CustomFilters'),
            'hasSortable'              => defined('NINJATABLESPRO_SORTABLE'),
            'ace_path_url'             => plugin_dir_url(__DIR__) . "assets/libs/ace",
            'upgradeGuide'             => 'https://wpmanageninja.com/r/docs/ninja-tables/how-to-install-and-upgrade/#upgrade',
            'hasValidLicense'          => get_option('_ninjatables_pro_license_status'),
            'i18n'                     => \NinjaTables\Classes\I18nStrings::getStrings(),
            'published_tables'         => $totalPublishedTable,
            'preview_required_scripts' => array(
                plugin_dir_url(__DIR__) . "assets/css/ninjatables-public.css",
                plugin_dir_url(__DIR__) . "public/libs/footable/js/footable.min.js",
                plugin_dir_url(__DIR__) . "public/libs/moment/moment.min.js",
                plugin_dir_url(__DIR__) . "assets/js/ninja-tables-footable." . NINJA_TABLES_ASSET_VERSION . ".js",
            ),
            'activated_features'       => apply_filters('ninja_table_activated_features', array(
                'default_tables'    => true,
                'fluentform_tables' => true
            )),
            'nt_integrity'             => $this->getIntegrity(),
            'admin_notices'            => apply_filters('ninja_dashboard_notices', []),
            'has_sql_permission'       => apply_filters('ninja_table_sql_permission', $isAdmin),
            'prefered_thumb'           => apply_filters('ninja_table_prefered_thumb', 'medium'),
            'has_woocommerce'          => defined('WC_PLUGIN_FILE'),
            'license_status'           => get_option('_ninjatables_pro_license_status'),
            'ninja_charts_url'         => defined('NINJA_CHARTS_VERSION') ? self_admin_url('admin.php?page=ninja-charts#/chart-list') : null,
            'ninja_table_admin_nonce'  => wp_create_nonce('ninja_table_admin_nonce'),
            'ninja_tables_pro_url'     => defined('NINJATABLESPRO') ? NINJAPROPLUGIN_URL : null
        ));

        // Elementor plugin have a bug where they throw error to parse #url, and I really don't know why they want to parse
        // other plugin's page's uri. They should fix it.
        // For now I am de-registering their script in ninja-table admin pages.
        wp_deregister_script('elementor-admin-app');

        // These last two line is for dumb devs who enqueue their scripts unversally
        // People should think what they are writing in their code 
        wp_dequeue_script('vue');
        wp_dequeue_script('vuejs');

        // We are gonna dequeue every other scripts on our pages.
        add_action('wp_print_scripts', function () {
            if (is_admin()) {
                $skip = apply_filters('ninja_table_skip_no_confict', false);

                if ($skip) return;

                global $wp_scripts;
                $pluginUrl = plugins_url();
                foreach ($wp_scripts->queue as $script) {
                    $src = $wp_scripts->registered[$script]->src;

                    if (strpos($src, $pluginUrl) !== false && !strpos($src, 'ninja-tables') !== false) {
                        wp_dequeue_script($wp_scripts->registered[$script]->handle);
                    }
                }
            }
        }, 1);
    }


    public function enqueue_data_tables_scripts()
    {
        if (isset($_GET['page']) && sanitize_text_field($_GET['page']) == 'ninja_tables') {
            $this->enqueue_scripts();
            $this->enqueue_styles();
        }
    }

    public function ajax_routes()
    {
        if (!ninja_table_admin_role()) {
            return;
        }

        ninjaTablesValidateNonce('ninja_table_admin_nonce');

        $valid_routes = array(
            'get-all-tables'           => 'getAllTables',
            'store-a-table'            => 'storeTable',
            'delete-a-table'           => 'deleteTable',
            'update-table-settings'    => 'updateTableSettings',
            'get-table-settings'       => 'getTableSettings',
            'get-table-data'           => 'getTableData',
            'store-table-data'         => 'storeData',
            'edit-data'                => 'editData',
            'delete-data'              => 'deleteData',
            'duplicate-table'          => 'duplicateTable',
            'export-data'              => 'exportData',
            'dismiss_fluent_suggest'   => 'dismissPluginSuggest',
            'save_custom_css_js'       => 'saveCustomCSSJS',
            'get_custom_css_js'        => 'getCustomCSSJS',
            'get_access_roles'         => 'getAccessRoles',
            'get_table_preview_html'   => 'getTablePreviewHtml',
            'set-external-data-source' => 'createTableWithExternalDataSource',
            'get_wp_post_types'        => 'getAllPostTypes',
            'get_wp_post_authors'      => 'getWPPostTypesAuthor',
            'save_wp_post_data_source' => 'createTableWithWPPostDataSource',
            'install_fluent_form'      => 'installFluentForm',
            'get_default_settings'     => 'getDefaultSettings',
            'save_default_settings'    => 'saveDefaultSettings',
            'get_button_settings'      => 'getButtonSettings',
            'update_button_settings'   => 'updateButtonSettings',
            'get_global_settings'      => 'getGlobalSettings',
            'update_global_settings'   => 'updateGlobalSettings',
            'clear_tables_cache'       => 'clearTablesCache',
            'update-single-cell'       => 'updateSingleCell',
            'install-extra-plugins'    => 'installExtraPlugins'
        );

        $importRoutes = array(
            'import-table'             => 'importTable',
            'upload-data'              => 'uploadData',
            'import-table-from-plugin' => 'importTableFromPlugin',
            'get-tables-from-plugin'   => 'getTablesFromPlugin',
        );


        $requested_route = sanitize_text_field($_REQUEST['target_action']);
        if (isset($valid_routes[$requested_route])) {
            $this->{$valid_routes[$requested_route]}();
        } else if (isset($importRoutes[$requested_route])) {
            $tableImport = new \NinjaTables\Classes\NinjaTableImport();
            $tableImport->{$importRoutes[$requested_route]}();
        }

        wp_die();
    }

    public function getAllTables()
    {
        $perPage = intval($_REQUEST['per_page']) ?: 10;

        $currentPage = intval($_GET['page']);

        $skip = $perPage * ($currentPage - 1);

        $args = array(
            'posts_per_page' => $perPage,
            'offset'         => $skip,
            'orderby'        => sanitize_text_field($_REQUEST['orderBy']),
            'order'          => sanitize_text_field($_REQUEST['order']),
            'post_type'      => $this->cpt_name,
            'post_status'    => 'any',
        );

        if (isset($_REQUEST['search']) && $_REQUEST['search']) {
            $args['s'] = sanitize_text_field($_REQUEST['search']);
        }

        $tables = get_posts($args);

        foreach ($tables as $table) {
            $provider = get_post_meta($table->ID, '_ninja_tables_data_provider', true);
            if ($provider === 'drag_and_drop') {
                $table->preview_url = site_url('?ninjatable_builder_preview=' . $table->ID);
            } else {
                $table->preview_url = site_url('?ninjatable_preview=' . $table->ID);
            }
            $dataSourceType = ninja_table_get_data_provider($table->ID);
            $table->dataSourceType = $dataSourceType;
            if ($dataSourceType == 'fluent-form') {
                $fluentFormFormId = get_post_meta($table->ID, '_ninja_tables_data_provider_ff_form_id', true);
                if ($fluentFormFormId) {
                    $table->fluentfrom_url = admin_url('admin.php?page=fluent_forms&route=entries&form_id=' . $fluentFormFormId);
                }
            } else if ($dataSourceType == 'csv' || $dataSourceType == 'google-csv') {
                $table->remoteURL = get_post_meta($table->ID, '_ninja_tables_data_provider_url', true);
            }
        }

        $tables = apply_filters('ninja_tables_get_all_tables', $tables);

        $total = wp_count_posts('ninja-table');
        $total = intval($total->publish);
        $lastPage = ceil($total / $perPage);

        wp_send_json(array(
            'total'        => $total,
            'per_page'     => $perPage,
            'current_page' => $currentPage,
            'last_page'    => ($lastPage) ? $lastPage : 1,
            'data'         => $tables,
        ), 200);
    }

    public function storeTable()
    {
        if (!sanitize_text_field($_REQUEST['post_title'])) {
            wp_send_json_error(array(
                'message' => __('The name field is required.', 'ninja-tables')
            ), 423);
        }

        $postId = intval($_REQUEST['tableId']);

        if (isset($_REQUEST['table_caption'])) {
            update_post_meta($postId, '_ninja_table_caption', sanitize_text_field($_REQUEST['table_caption']));
        }

        wp_send_json(array(
            'table_id' => $this->saveTable($postId),
            'message'  => __('Table ' . ($postId ? 'updated' : 'created') . ' successfully.', 'ninja-tables')
        ), 200);
    }

    protected function saveTable($postId = null)
    {
        $attributes = array(
            'post_title'   => sanitize_text_field($_REQUEST['post_title']),
            'post_content' => wp_kses_post($_REQUEST['post_content']),
            'post_type'    => $this->cpt_name,
            'post_status'  => 'publish'
        );

        if (!$postId) {
            $postId = wp_insert_post($attributes);
        } else {
            $attributes['ID'] = $postId;
            wp_update_post($attributes);
        }
        update_post_meta($postId, '_last_edited_by', get_current_user_id());
        update_post_meta($postId, '_last_edited_time', date('Y-m-d H:i:s'));

        return $postId;
    }

    public function saveCustomCSSJS()
    {
        $tableId = intval($_REQUEST['table_id']);
        $css = sanitize_textarea_field($_REQUEST['custom_css']);
        $css = wp_strip_all_tags($css);
        update_post_meta($tableId, '_ninja_tables_custom_css', $css);

        do_action('ninja_tables_custom_code_before_save', $_REQUEST);

        wp_send_json_success(array(
            'message' => 'Code successfully saved'
        ), 200);
    }

    public function getCustomCSSJS()
    {
        $tableId = intval($_REQUEST['table_id']);
        wp_send_json_success(array(
            'custom_css' => get_post_meta($tableId, '_ninja_tables_custom_css', true),
            'custom_js'  => get_post_meta($tableId, '_ninja_tables_custom_js', true),
        ), 200);
    }

    public function getTableSettings()
    {
        $table = get_post($tableID = intval($_REQUEST['table_id']));
        if (!$table || $table->post_type != 'ninja-table') {
            wp_send_json_error(array(
                'message' => __('No Table Found'),
                'route'   => 'home'
            ), 423);
        }
        $provider = ninja_table_get_data_provider($table->ID);

        $table = apply_filters('ninja_tables_get_table_' . $provider, $table);

        $table->table_caption = get_post_meta($tableID, '_ninja_table_caption', true);

        $table->custom_css = get_post_meta($tableID, '_ninja_tables_custom_css', true);

        $this->checkDBMigrations();

        wp_send_json(array(
            'preview_url' => site_url('?ninjatable_preview=' . $tableID),
            'columns'     => ninja_table_get_table_columns($tableID, 'admin'),
            'settings'    => ninja_table_get_table_settings($tableID, 'admin'),
            'table'       => $table,
        ), 200);
    }

    public function updateTableSettings()
    {
        $tableId = intval($_REQUEST['table_id']);

        $tableColumns = array();

        if (isset($_REQUEST['columns'])) {

            $rawColumns =  apply_filters('ninja_tables_before_update_settings', ninja_tables_sanitize_array($_REQUEST['columns']), $tableId);
            $provider = ninja_table_get_data_provider($tableId);

            if ($rawColumns && is_array($rawColumns)) {
                foreach ($rawColumns as $column) {
                    foreach ($column as $column_index => $column_value) {
                        if ($provider === 'google-csv' && gettype($column_value) === 'string') {
                            $column_value = htmlspecialchars_decode($column_value);
                        }
                        if (is_int($column_value)) {
                            $column[$column_index] = intval($column_value);
                        } else {
                            $column[$column_index] = $column_value;
                        }
                    }
                    $tableColumns[] = $column;
                }
                $tableColumns = apply_filters('ninja_table_update_columns_' . ninja_table_get_data_provider($tableId), $tableColumns, $rawColumns, $tableId);
                do_action('ninja_table_before_update_columns_' . ninja_table_get_data_provider($tableId), $tableColumns, $rawColumns, $tableId);
                update_post_meta($tableId, '_ninja_table_columns', $tableColumns);
            }
        }

        $formattedTablePreference = array();

        if (isset($_REQUEST['table_settings'])) {
            $tablePreference = ninja_tables_sanitize_array($_REQUEST['table_settings']);
            if ($tablePreference && is_array($tablePreference)) {
                $formattedTablePreference = ninjaTableNormalize($tablePreference);
                update_post_meta($tableId, '_ninja_table_settings', $formattedTablePreference);
            }
        }

        ninjaTablesClearTableDataCache($tableId);

        update_post_meta($tableId, '_last_edited_by', get_current_user_id());
        update_post_meta($tableId, '_last_edited_time', date('Y-m-d H:i:s'));

        wp_send_json(array(
            'message'  => __('Successfully updated configuration.', 'ninja-tables'),
            'columns'  => $tableColumns,
            'settings' => $formattedTablePreference
        ), 200);
    }

    public function getTable()
    {
        $tableId = intval($_REQUEST['id']);
        $table = get_post($tableId);

        if ($table) {
            $table->table_caption = get_post_meta($tableId, '_ninja_table_caption', true);
        }

        wp_send_json(array(
            'data' => $table
        ), 200);
    }

    public function deleteTable()
    {
        $tableId = intval($_REQUEST['table_id']);

        if (get_post_type($tableId) != $this->cpt_name) {
            wp_send_json(array(
                'message' => __('Invalid Table to Delete', 'ninja-tables')
            ), 300);
        }


        wp_delete_post($tableId, true);
        // Delete the post metas
        delete_post_meta($tableId, '_ninja_table_columns');
        delete_post_meta($tableId, '_ninja_table_settings');
        delete_post_meta($tableId, '_ninja_table_cache_object');
        // now delete the data
        try {
            ninja_tables_DbTable()->where('table_id', $tableId)->delete();
        } catch (Exception $e) {
            //
        }

        wp_send_json(array(
            'message' => __('Successfully deleted the table.', 'ninja-tables')
        ), 200);
    }

    public function getTableData()
    {
        $perPage = isset($_REQUEST['per_page']) ? intval($_REQUEST['per_page']) : 10;
        $currentPage = isset($_REQUEST['page']) ? intval($_REQUEST['page']) : 1;
        $skip = $perPage * ($currentPage - 1);
        $tableId = intval($_REQUEST['table_id']);
        $search = sanitize_text_field($_REQUEST['search']);

        $dataSourceType = ninja_table_get_data_provider($tableId);
        if ($dataSourceType == 'default') {
            list($orderByField, $orderByType) = $this->getTableSortingParams($tableId);

            $query = ninja_tables_DbTable()->where('table_id', $tableId);
            if ($search) {
                $query->search($search, array('value'));
            }
            $data = $query->take($perPage)
                ->skip($skip)
                ->limit($perPage)
                ->orderBy($orderByField, $orderByType)
                ->get();

            $total = ninja_tables_DbTable()->where('table_id', $tableId)->count();

            $response = array();

            $hasSettings = true;
            foreach ($data as $item) {
                $hasSettings = property_exists($item, 'settings');
                $settings = (object)array();
                if ($hasSettings) {
                    $settings = maybe_unserialize($item->settings);
                    if (!is_array($settings)) {
                        $settings = (object)array();
                    }
                }
                $createdBy = '';
                if (property_exists($item, 'owner_id')) {
                    $userInfo = get_userdata($item->owner_id);
                    if ($userInfo && property_exists($userInfo->data, 'display_name')) {
                        $createdBy = $userInfo->data->display_name;
                    }
                }
                $response[] = array(
                    'id'         => $item->id,
                    'created_at' => $item->created_at,
                    'settings'   => $settings,
                    'created_by' => $createdBy,
                    'position'   => property_exists($item, 'position') ? $item->position : null,
                    'values'     => json_decode($item->value, true)
                );
            }

            if (!$hasSettings) {
                // We have to migrate the data now
            }

        } else {
            list($response, $total) = apply_filters(
                'ninja_tables_get_table_data_' . $dataSourceType,
                array(array(), 0),
                $tableId,
                $perPage,
                $skip
            );
        }

        // Needed for other data source providers
        list($response, $total) = apply_filters(
            'ninja_tables_get_table_data',
            array($response, $total),
            $tableId,
            $perPage,
            $skip
        );

        wp_send_json(array(
            'total'        => $total,
            'per_page'     => $perPage,
            'current_page' => $currentPage,
            'last_page'    => ceil($total / $perPage),
            'data'         => $response,
            'data_source'  => $dataSourceType
        ), 200);
    }

    /**
     * Get the order by field and order by type values.
     *
     * @param        $tableId
     * @param null $tableSettings
     *
     * @return array
     */
    protected function getTableSortingParams($tableId, $tableSettings = null)
    {
        $tableSettings = $tableSettings ?: ninja_table_get_table_settings($tableId, 'admin');

        $orderByField = 'created_at';
        $orderByType = 'DESC';

        if (isset($tableSettings['sorting_type'])) {
            if ($tableSettings['sorting_type'] === 'manual_sort') {
                $orderByField = 'position';
                $orderByType = 'ASC';
            } elseif ($tableSettings['sorting_type'] === 'by_created_at') {
                $orderByField = 'created_at';
                if ($tableSettings['default_sorting'] === 'new_first') {
                    $orderByType = 'DESC';
                } else {
                    $orderByType = 'ASC';
                }
            }
        }
        return [$orderByField, $orderByType];
    }

    public function storeData()
    {
        $tableId = intval($_REQUEST['table_id']);

        if (user_can_richedit()) {
            $row = ninja_tables_sanitize_table_content_array(ArrayHelper::get($_REQUEST, 'row', []), $tableId);
        } else {
            ninja_tables_allowed_css_properties();
            $row = ninja_tables_sanitize_array(ArrayHelper::get($_REQUEST, 'row', []));
        }

        $formattedRow = array();

        foreach ($row as $key => $item) {
            $formattedRow[$key] = wp_unslash($item);
        }

        $attributes = array(
            'table_id'   => $tableId,
            'attribute'  => 'value',
            'value'      => json_encode($formattedRow, JSON_UNESCAPED_UNICODE),
            'owner_id'   => get_current_user_id(),
            'updated_at' => date('Y-m-d H:i:s')
        );

        if (isset($_REQUEST['settings'])) {
            $attributes['settings'] = maybe_serialize(
                wp_unslash(
                    ninja_tables_sanitize_array($_REQUEST['settings'])
                )
            );
        }

        $createdAt = '';
        if (isset($_REQUEST['created_at'])) {
            $createdAt = sanitize_text_field($_REQUEST['created_at']);
        }

        if ($createdAt) {
            $attributes['created_at'] = $createdAt;
        }

        if ($id = intval($_REQUEST['id'])) {
            do_action('ninja_table_before_update_item', $id, $tableId, $attributes);
            ninja_tables_DbTable()->where('id', $id)->update($attributes);
            do_action('ninja_table_after_update_item', $id, $tableId, $attributes);
        } else {
            if (isset($_REQUEST['insert_after_id'])) {
                list($orderByField, $orderByType) = $this->getTableSortingParams($tableId);
                if ($orderByField == 'created_at') {
                    // Calculate the insert position Date
                    $prevItemId = absint($_REQUEST['insert_after_id']);
                    $previousItem = ninja_tables_DbTable()
                        ->where('id', $prevItemId)
                        ->first();
                    if ($previousItem) {
                        if ($orderByType == 'ASC') {
                            // ASC means, We have to minus time to created_at
                            $newDateStamp = strtotime($previousItem->created_at) + 1;
                        } else {
                            $newDateStamp = strtotime($previousItem->created_at) - 1;
                        }
                        $attributes['created_at'] = date('Y-m-d H:i:s', $newDateStamp);
                        $this->fixCreatedAtDate($tableId, $previousItem->created_at, $orderByType);
                    }
                }
            }

            if (!isset($attributes['created_at'])) {
                $attributes['created_at'] = date('Y-m-d H:i:s');
            }

            $attributes = apply_filters('ninja_tables_item_attributes', $attributes);

            do_action('ninja_table_before_add_item', $tableId, $attributes);
            $id = $insertId = ninja_tables_DbTable()->insert($attributes);
            do_action('ninja_table_after_add_item', $insertId, $tableId, $attributes);
        }

        $item = ninja_tables_DbTable()->find($id);

        ninjaTablesClearTableDataCache($tableId);

        update_post_meta($tableId, '_last_edited_by', get_current_user_id());
        update_post_meta($tableId, '_last_edited_time', date('Y-m-d H:i:s'));

        $itemSettings = maybe_unserialize($item->settings);
        if (!is_array($itemSettings)) {
            $itemSettings = (object)array();
        }

        wp_send_json(array(
            'message' => __('Successfully saved the data.', 'ninja-tables'),
            'item'    => array(
                'id'         => $item->id,
                'values'     => $formattedRow,
                'row'        => json_decode($item->value),
                'created_at' => $item->created_at,
                'settings'   => $itemSettings,
                'position'   => property_exists($item, 'position') ? $item->position : null
            )
        ), 200);
    }

    public function updateSingleCell()
    {
        $rowId = intval($_REQUEST['row_id']);

        // get The row first
        $row = ninja_tables_DbTable()
            ->where('id', $rowId)
            ->first();

        if (user_can_richedit()) {
            $data = ninja_tables_sanitize_table_content_array($_REQUEST, $row->table_id);
        } else {
            ninja_tables_allowed_css_properties();
            $data = ninja_tables_sanitize_array($_REQUEST);
        }

        $columnKey = sanitize_text_field($data['column_key']);
        $columnValue = wp_unslash($data['column_value']);


        $values = json_decode($row->value, true);
        $values[$columnKey] = $columnValue;
        ninja_tables_DbTable()
            ->where('id', $rowId)
            ->update([
                'value'      => json_encode($values, JSON_UNESCAPED_UNICODE),
                'updated_at' => date('Y-m-d H:i:s')
            ]);

        ninjaTablesClearTableDataCache($row->table_id);
        update_post_meta($row->table_id, '_last_edited_by', get_current_user_id());
        update_post_meta($row->table_id, '_last_edited_time', date('Y-m-d H:i:s'));


        wp_send_json_success([
            'message' => 'Cell successfully updated'
        ]);
    }

    private function fixCreatedAtDate($tableId, $refDate, $orderType)
    {
        global $wpdb;
        $tableName = $wpdb->prefix . ninja_tables_db_table_name();
        if ($orderType == 'ASC') {
            $query = "UPDATE {$tableName}
                  SET created_at = ADDTIME(created_at, 2)
                  WHERE table_id = %d
                  AND created_at > %s";
        } else {
            $orderType = 'DESC';
            $query = "UPDATE {$tableName}
                  SET created_at = SUBTIME(created_at, 2)
                  WHERE table_id = %d
                  AND created_at < %s";
        }

        $bindings = [
            $tableId,
            $refDate
        ];
        $query .= " ORDER BY created_at " . $orderType;
        $wpdb->query($wpdb->prepare($query, $bindings));
    }

    public function deleteData()
    {
        $data = ninja_tables_sanitize_array($_REQUEST);
        $tableId = intval($data['table_id']);

        $id = $data['id'];

        $ids = is_array($id) ? $id : array($id);

        $ids = array_map(function ($item) {
            return intval($item);
        }, $ids);

        add_action('ninja_table_before_items_deleted', $ids, $tableId);
        ninja_tables_DbTable()->where('table_id', $tableId)->whereIn('id', $ids)->delete();
        add_action('ninja_table_after_items_deleted', $ids, $tableId);

        ninjaTablesClearTableDataCache($tableId);

        wp_send_json(array(
            'message' => __('Successfully deleted data.', 'ninja-tables')
        ), 200);
    }

    public function exportData()
    {
        $format = sanitize_text_field($_REQUEST['format']);

        $tableId = intval($_REQUEST['table_id']);

        $tableTitle = get_the_title($tableId);

        $fileName = sanitize_title($tableTitle, 'Export-Table-' . date('Y-m-d-H-i-s'), 'preview');

        $tableColumns = ninja_table_get_table_columns($tableId, 'admin');

        $tableSettings = ninja_table_get_table_settings($tableId, 'admin');

        if ($format == 'csv') {

            $sortingType = ArrayHelper::get($tableSettings, 'sorting_type', 'by_created_at');

            $tableColumns = ninja_table_get_table_columns($tableId, 'admin');
            $data = ninjaTablesGetTablesDataByID($tableId, $tableColumns, $sortingType, true);

            $header = array();

            foreach ($tableColumns as $item) {
                $header[$item['key']] = $item['name'];
            }

            $exportData = array();

            foreach ($data as $item) {
                $temp = array();
                foreach ($header as $accessor => $name) {
                    $value = \NinjaTables\Classes\ArrayHelper::get($item, $accessor);
                    if (is_array($value)) {
                        $value = implode(', ', $value);
                    }
                    $temp[] = ninjaTablesSanitizeForCSV($value);
                }
                array_push($exportData, $temp);
            }
            $this->exportAsCSV(array_values($header), $exportData, $fileName . '.csv');
        } elseif ($format == 'json') {
            $table = get_post($tableId);

            $dataProvider = ninja_table_get_data_provider($tableId);
            $rows = array();
            if ($dataProvider == 'default') {
                $rawRows = ninja_tables_DbTable()
                    ->select(array('position', 'owner_id', 'attribute', 'value', 'settings', 'created_at', 'updated_at'))
                    ->where('table_id', $tableId)
                    ->get();
                foreach ($rawRows as $row) {
                    $row->value = json_decode($row->value, true);
                    $rows[] = $row;
                }
            }

            $matas = get_post_meta($tableId);
            $allMeta = array();

            $excludedMetaKeys = array(
                '_ninja_table_cache_object',
                '_ninja_table_cache_html',
                '_external_cached_data',
                '_last_external_cached_time',
                '_last_edited_by',
                '_last_edited_time',
                '__ninja_cached_table_html'
            );

            foreach ($matas as $metaKey => $metaValue) {
                if (!in_array($metaKey, $excludedMetaKeys)) {
                    if (isset($metaValue[0])) {
                        $metaValue = maybe_unserialize($metaValue[0]);
                        $allMeta[$metaKey] = $metaValue;
                    }
                }
            }

            $exportData = array(
                'post'          => $table,
                'columns'       => $tableColumns,
                'settings'      => $tableSettings,
                'data_provider' => $dataProvider,
                'metas'         => $allMeta,
                'rows'          => array(),
                'original_rows' => $rows
            );
            $this->exportAsJSON($exportData, $fileName . '.json');
        }
    }

    private function exportAsCSV($header, $data, $fileName = null)
    {
        $fileName = ($fileName) ? $fileName : 'export-data-' . date('d-m-Y') . '.csv';

        $writer = \League\Csv\Writer::createFromFileObject(new SplTempFileObject());
        $writer->setDelimiter(",");
        $writer->setNewline("\r\n");
        $writer->insertOne($header);
        $writer->insertAll($data);
        $writer->output($fileName);
        die();
    }

    private function exportAsJSON($data, $fileName = null)
    {
        $fileName = ($fileName) ? $fileName : 'export-data-' . date('d-m-Y') . '.json';

        header('Content-disposition: attachment; filename=' . $fileName);

        header('Content-type: application/json');

        echo json_encode($data); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

        die();
    }

    public function add_tabales_to_editor()
    {
        $pages_with_editor_button = array('post.php', 'post-new.php');
        foreach ($pages_with_editor_button as $editor_page) {
            add_action("load-{$editor_page}", array($this, 'init_ninja_mce_buttons'));
        }
    }

    public function init_ninja_mce_buttons()
    {
        if (!user_can_richedit()) {
            return;
        }
        add_filter("mce_external_plugins", array($this, 'ninja_table_add_button'));
        add_filter('mce_buttons', array($this, 'ninja_table_register_button'));
        add_action('admin_footer', array($this, 'pushNinjaTablesToEditorFooter'));
    }

    public function pushNinjaTablesToEditorFooter()
    {
        $tables = $this->getAllTablesForMce();
        ?>
        <script type="text/javascript">
            window.ninja_tables_tiny_mce = {
                label: '<?php _e('Select a Table to insert', 'ninja-tables') ?>',
                title: '<?php _e('Insert Ninja Tables Shortcode', 'ninja-tables') ?>',
                select_error: '<?php _e('Please select a table'); ?>',
                insert_text: '<?php _e('Insert Shortcode', 'ninja-tables'); ?>',
                tables: <?php echo json_encode($tables); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $tables is already escaped before being passed in. ?>,
                logo: '<?php echo esc_url(NINJA_TABLES_DIR_URL . 'assets/img/ninja-table-editor-button-2x.png'); ?>'
            }
        </script>
        <?php
    }

    private function getAllTablesForMce()
    {
        $args = array(
            'posts_per_page' => -1,
            'orderby'        => 'date',
            'order'          => 'DESC',
            'post_type'      => $this->cpt_name,
            'post_status'    => 'any'
        );

        $tables = get_posts($args);
        $formatted = array();

        $title = __('Select a Table', 'ninja-tables');
        if (!$tables) {
            $title = __('No Tables found. Please add a table first');
        }
        $formatted[] = array(
            'text'  => $title,
            'value' => ''
        );

        foreach ($tables as $table) {
            $formatted[] = array(
                'text'          => esc_attr($table->post_title),
                'value'         => $table->ID,
                'data_source'   => esc_attr(ninja_table_get_data_provider($table->ID))
            );
        }

        return $formatted;
    }

    /**
     * add a button to Tiny MCE editor
     *
     * @param $plugin_array
     *
     * @return mixed
     */
    public function ninja_table_add_button($plugin_array)
    {
        $plugin_array['ninja_table'] = NINJA_TABLES_DIR_URL . 'assets/js/ninja-table-tinymce-button.js';

        return $plugin_array;
    }

    /**
     * register a button to Tiny MCE editor
     *
     * @param $buttons
     *
     * @return mixed
     */
    public function ninja_table_register_button($buttons)
    {
        array_push($buttons, 'ninja_table');

        return $buttons;
    }

    public function dismissPluginSuggest()
    {
        update_option('_ninja_tables_plugin_suggest_dismiss', time());
    }

    /**
     * Save a flag if the a post/page/cpt have [ninja_tables] shortcode
     *
     * @param int $post_id
     *
     * @return void
     */
    public function saveNinjaTableFlagOnShortCode($post_id)
    {
        if (isset($_POST['post_content'])) {
            $post_content = wp_kses_post($_POST['post_content']);
        } else {
            $post = get_post($post_id);
            $post_content = $post->post_content;
        }

        $ids = ninjaTablesGetShortCodeIds($post_content);

        if ($ids) {
            update_post_meta($post_id, '_has_ninja_tables', $ids);
        } elseif (get_post_meta($post_id, '_has_ninja_tables', true)) {
            update_post_meta($post_id, '_has_ninja_tables', 0);
        }
    }

    public function duplicateTable()
    {
        $oldPostId = intval($_REQUEST['tableId']);

        $this->checkDBMigrations();
        $post = get_post($oldPostId);

        // Duplicate table itself.
        $attributes = array(
            'post_title'   => $post->post_title . '( Duplicate )',
            'post_content' => $post->post_content,
            'post_type'    => $post->post_type,
            'post_status'  => 'publish'
        );

        $newPostId = wp_insert_post($attributes);

        global $wpdb;

        // Duplicate table settings.
        $postMetas = get_post_meta($oldPostId);

        foreach ($postMetas as $metaKey => $metaValue) {
            update_post_meta($newPostId, $metaKey, maybe_unserialize($metaValue[0]));
        }

        // Duplicate table rows.
        $itemsTable = $wpdb->prefix . ninja_tables_db_table_name();

        $sql = "INSERT INTO $itemsTable (`position`, `table_id`, `owner_id`, `settings`, `attribute`, `value`, `created_at`, `updated_at`)";
        $sql .= " SELECT `position`, $newPostId, `owner_id`, `settings`, `attribute`, `value`, `created_at`, `updated_at` FROM $itemsTable";
        $sql .= " WHERE `table_id` = $oldPostId";

        $wpdb->query($sql);

        wp_send_json_success(array(
            'message'  => __('Successfully duplicated table.', 'ninja-tables'),
            'table_id' => $newPostId
        ), 200);
    }

    public function getAccessRoles()
    {
        $roles = get_editable_roles();
        $formatted = array();
        $excludedRoles = array('subscriber', 'administrator');
        foreach ($roles as $key => $role) {
            if (!in_array($key, $excludedRoles)) {
                $formatted[] = array(
                    'name' => $role['name'],
                    'key'  => $key
                );
            }
        }

        $capability = get_option('_ninja_tables_permission');

        if (is_string($capability)) {
            $capability = [];
        }

        wp_send_json(array(
            'capability'     => $capability,
            'roles'          => $formatted,
            'sql_permission' => get_option('_ninja_tables_sql_permission')
        ), 200);
    }

    public function getTablePreviewHtml()
    {
        $tableId = intval($_REQUEST['table_id']);
        $tableColumns = ninja_table_get_table_columns($tableId, 'public');
        $tableSettings = ninja_table_get_table_settings($tableId, 'public');

        $formattedColumns = [];
        foreach ($tableColumns as $index => $column) {
            $formattedColumn = NinjaFooTable::getFormattedColumn($column, $index, $tableSettings, true,
                'by_created_at');
            $formattedColumn['original'] = $column;
            $formattedColumns[] = $formattedColumn;
        }

        $formatted_data = ninjaTablesGetTablesDataByID($tableId, $tableColumns, $tableSettings['default_sorting'], true, 25);

        if (count($formatted_data) > 25) {
            $formatted_data = array_slice($formatted_data, 0, 25);
        }

        echo ninjaTablesLoadView('public/views/table_inner_html', array(
            'table_columns' => $formattedColumns,
            'table_rows'    => $formatted_data
        ));
    }

    public function checkDBMigrations()
    {
        $this->migrateIdAndTableIdColumn();
        $firstRow = ninja_tables_DbTable()->first();

        if (!$firstRow) {
            if (get_option('_ninja_table_db_settings_owner_id')) {
                return true;
            }
            $this->migrateSettingColumnIfNeeded();
            $this->migrateOwnerColumnIfNeeded();
            update_option('_ninja_table_db_settings_owner_id', true);
            return true;
        }
        if (!property_exists($firstRow, 'owner_id')) {
            $this->migrateOwnerColumnIfNeeded();
        }
        if (!property_exists($firstRow, 'settings')) {
            $this->migrateSettingColumnIfNeeded();
        }
        if (!property_exists($firstRow, 'position')) {
            $this->migratePositionDatabase();
        }
        return true;
    }

    public function migrateIdAndTableIdColumn()
    {
        global $wpdb;
        $tableName = $wpdb->prefix . ninja_tables_db_table_name();
        $sql = "SELECT 
            DATA_TYPE
            FROM INFORMATION_SCHEMA.COLUMNS 
            WHERE TABLE_SCHEMA = '" . DB_NAME . "'
            AND TABLE_NAME = '" . $tableName . "'
            AND COLUMN_NAME = 'id'
        ";
        $results = $wpdb->get_results($sql);
        $dataType = $results[0]->DATA_TYPE;

        if ($dataType == 'int') {
            $sql = "ALTER TABLE $tableName 
            MODIFY COLUMN id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, 
            MODIFY COLUMN table_id BIGINT(20) UNSIGNED NOT NULL";
            $wpdb->query($sql);
        }

    }

    public function migratePositionDatabase()
    {
        // If the database is already migrated for manual
        // sorting the option table would have a flag.
        $option = '_ninja_tables_sorting_migration';
        global $wpdb;
        $tableName = $wpdb->prefix . ninja_tables_db_table_name();

        // Update the databse to hold the sorting position number.
        $sql = "ALTER TABLE $tableName ADD COLUMN `position` INT(11) AFTER `id`;";

        $wpdb->query($sql);
        // Keep a flag on the options table that the
        // db is migrated to use for manual sorting.
        update_option($option, true);
    }

    private function migrateSettingColumnIfNeeded()
    {
        global $wpdb;
        $tableName = $wpdb->prefix . ninja_tables_db_table_name();
        // Update the databse to hold the sorting position number.
        $sql = "ALTER TABLE $tableName ADD COLUMN `settings` LONGTEXT AFTER `value`;";
        ob_start();
        $wpdb->query($sql);
        $maybeError = ob_get_clean();
        update_option('_ninja_tables_settings_migration', true);
    }

    private function migrateOwnerColumnIfNeeded()
    {
        global $wpdb;
        $tableName = $wpdb->prefix . ninja_tables_db_table_name();
        // Update the databse to hold the sorting position number.
        $sql = "ALTER TABLE $tableName ADD COLUMN `owner_id` int(11) AFTER `table_id`;";
        ob_start();
        $wpdb->query($sql);
        $maybeError = ob_get_clean();
    }

    public function getAllPostTypes()
    {
        global $wpdb;

        $postStatuses = ninjaTablesGetPostStatuses();
        $post_fields = $wpdb->get_col("DESC {$wpdb->prefix}posts");

        $publicPostTypes = get_post_types(array(
            'public' => true
        ));

        $excludedTypes = apply_filters('ninja_table_excluded_post_types', array(
            'ninja-table',
            'revision',
            'nav_menu_item',
            'oembed_cache',
            'user_request',
            'acf-field-group',
            'acf-field'
        ));

        $all_post_types = array_diff(get_post_types(), $excludedTypes);

        $post_types = array(
            'public'  => array(),
            'private' => array()
        );

        foreach ($all_post_types as $type) {
            $taxonomies = get_object_taxonomies($type);
            $taxonomies = array_combine($taxonomies, $taxonomies);

            foreach ($taxonomies as $taxonomy) {
                $taxonomies[$taxonomy] = get_terms([
                    'taxonomy'   => $taxonomy,
                    'hide_empty' => false,
                ]);
            }

            $status = isset($publicPostTypes[$type]) ? 'public' : 'private';

            $post_types[$status][$type] = array(
                'status'     => $status,
                'taxonomies' => $taxonomies,
                'fields'     => array_map(function ($taxonomy) use ($type) {
                    return "{$type}.{$taxonomy}";
                }, array_keys($taxonomies))
            );
        }

        if ($post_types['private']) {
            $post_types = array_merge($post_types['public'], $post_types['private']);
        } else {
            $post_types = $post_types['public'];
        }

        wp_send_json_success(
            compact('post_fields', 'post_types', 'postStatuses'), 200
        );
    }

    public function getWPPostTypesAuthor()
    {
        $authors = array();
        if (isset($_REQUEST['post_types'])) {
            $postTypes = ninja_tables_sanitize_array($_REQUEST['post_types']);
            if ($postTypes) {
                global $wpdb;
                $postTypes = implode("','", $postTypes);
                $authors = $wpdb->get_results("SELECT {$wpdb->prefix}users.ID, {$wpdb->prefix}users.display_name FROM {$wpdb->prefix}posts INNER JOIN {$wpdb->prefix}users ON {$wpdb->prefix}users.ID = {$wpdb->prefix}posts.post_author WHERE {$wpdb->prefix}posts.post_type IN ('" . $postTypes . "') GROUP BY {$wpdb->prefix}posts.post_author");
            }
        }
        wp_send_json_success(array(
            'authors' => $authors
        ));
    }

    public function installFluentForm()
    {
        if (!current_user_can('install_plugins')) {
            wp_send_json_error(array(
                'message' => __('You do not have permission to install a plugin, Please ask your administrator to install WP Fluent Form')
            ), 423);
            return;
        }

        if (is_multisite()) {
            wp_send_json_error(array(
                'message' => __('You are using wp multisite environment so please install WP FluentForm manually')
            ), 423);
            return;
        }

        $result = $this->install_plugin('fluentform', 'fluentform.php');
        $status = !is_wp_error($result);

        if ($status) {
            wp_send_json_success(array(
                'message'      => __('WP Fluent Form successfully installed and activated, You are redirecting to WP Fluent Form Now'),
                'redirect_url' => admin_url('admin.php?page=fluent_forms')
            ), 200);
            return;
        } else {
            wp_send_json_error(array(
                'message' => __('There was an error to install the plugin. Please install the plugin manually.')
            ), 423);
            return;
        }
    }

    public function install_plugin($slug, $file)
    {
        include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
        include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';

        $plugin_basename = $slug . '/' . $file;

        // if exists and not activated
        if (file_exists(WP_PLUGIN_DIR . '/' . $plugin_basename)) {
            return activate_plugin($plugin_basename);
        }

        // seems like the plugin doesn't exists. Download and activate it
        $upgrader = new Plugin_Upgrader(new WP_Ajax_Upgrader_Skin());

        $api = plugins_api('plugin_information', array('slug' => $slug, 'fields' => array('sections' => false)));
        $result = $upgrader->install($api->download_link);

        if (is_wp_error($result)) {
            return $result;
        }

        return activate_plugin($plugin_basename);
    }

    public function getDefaultSettings()
    {
        $settings = getDefaultNinjaTableSettings();
        wp_send_json_success(array(
            'default_settings' => $settings
        ), 200);
    }

    public function saveDefaultSettings()
    {
        $settings = ninjaTableNormalize(wp_unslash($_REQUEST['default_settings']));
        update_option('_ninja_table_default_appearance_settings', $settings);
        wp_send_json_success(array(
            'message' => __('Settings successfully updated', 'ninja-tables')
        ), 200);
    }

    public function getButtonSettings()
    {
        $tableId = absint($_REQUEST['table_id']);
        $tableButtonDefaults = array(
            'csv'              => array(
                'status'     => 'no',
                'label'      => 'CSV',
                'all_rows'   => 'no',
                'bg_color'   => 'rgb(0,0,0)',
                'text_color' => 'rgb(255,255,255)'
            ),
            'print'            => array(
                'status'           => 'no',
                'label'            => 'Print',
                'all_rows'         => 'no',
                'bg_color'         => 'rgb(0,0,0)',
                'text_color'       => 'rgb(255,255,255)',
                'header_each_page' => 'no',
                'footer_each_page' => 'no',
            ),
            'button_position'  => 'after_search_box',
            'button_alignment' => 'ninja_buttons_right'
        );

        $tableButtons = get_post_meta($tableId, '_ninja_custom_table_buttons', true);
        if (!$tableButtons) {
            $tableButtons = array();
        }

        $tableButtons = array_replace_recursive($tableButtonDefaults, $tableButtons);

        wp_send_json_success(array(
            'button_settings' => $tableButtons
        ));
    }

    public function updateButtonSettings()
    {
        $tableId = absint($_REQUEST['table_id']);
        $buttonSettings = wp_unslash(ninja_tables_sanitize_array($_REQUEST['button_settings']));
        update_post_meta($tableId, '_ninja_custom_table_buttons', $buttonSettings);
        wp_send_json_success(array(
            'message' => __('Settings successfully updated', 'ninja-tables')
        ), 200);
    }

    public function add_plugin_action_links($links)
    {

        if (!defined('NINJATABLESPRO')) {
            $links[] = '<a style="color: green; font-weight: bold;" target="_blank" href="https://wpmanageninja.com/downloads/ninja-tables-pro-add-on/">Go Pro</a>';
        }

        $links[] = '<a href="' . admin_url('admin.php?page=ninja_tables#/') . '">' . __('All Tables', 'ninja-tables') . '</a>';

        return $links;
    }

    public function getGlobalSettings()
    {
        $suppressError = get_option('_ninja_suppress_error');
        if (!$suppressError) {
            $suppressError = 'no';
        }

        wp_send_json_success(array(
            'ninja_suppress_error' => $suppressError
        ), 200);
    }

    public function updateGlobalSettings()
    {
        $errorHandling = sanitize_text_field($_REQUEST['suppress_error']);
        update_option('_ninja_suppress_error', $errorHandling, true);
        wp_send_json_success(array(
            'message' => __('Settings successfully updated', 'ninja-tables')
        ), 200);
    }

    private function getIntegrity()
    {
        if (defined('NINJATABLESPRO')) {
            if (is_multisite()) {
                return 'valid';
            }
            $status = get_option('_ninjatables_pro_license_status');
            if (is_multisite() && $status != 'valid') {
                $status = get_network_option(get_main_network_id(), '_ninjatables_pro_license_status');
            }
            if ($status == 'valid') {
                $key = get_option('_ninjatables_pro_license_key');
                if (is_multisite()) {
                    $key = get_network_option(get_main_network_id(), '_ninjatables_pro_license_key');
                }
                $length = strlen($key);
                if ($length < 20) {
                    return apply_filters('ninja_table_integrity', 'nope');
                }
            }
        }
        return apply_filters('ninja_table_integrity', 'valid');
    }

    public function clearTablesCache()
    {
        ninja_table_clear_all_cache();
        wp_send_json_success(array(
            'message' => __('All Cache successfully cleared', 'ninja_tables')
        ), 200);
    }

    /**
     * Installs extra plugins when necessary.
     */
    private function installExtraPlugins()
    {
        $plugin = [
            'name'      => 'Ninja Charts',
            'repo-slug' => 'ninja-charts',
            'file'      => 'ninja-charts.php',
            'redirect'  => self_admin_url('admin.php?page=ninja-charts#/chart-list')
        ];

        (new \NinjaTables\Classes\BackgroundInstaller())->install($plugin);

        wp_send_json_success(array(
            'message'  => 'Successfully enabled Ninja Charts.',
            'redirect' => $plugin['redirect']
        ));
    }

    public function pluginUpdateActions($upgrader_object, $options)
    {
        if ($options['action'] == 'update' && $options['type'] === 'plugin') {
            if (in_array(NINJA_TABLES_BASENAME, $options['plugins'])) {
                do_action('ninja_table_check_db_integrity');
            }
        }
    }
}
