<?php
namespace NinjaTablesPro\DataProviders;

class CsvProvider
{
    public function boot()
    {
        add_filter('ninja_tables_get_table_google-csv', array($this, 'getTableSettings'));
        add_filter('ninja_tables_get_table_csv', array($this, 'getTableSettings'));
        add_filter('ninja_tables_get_table_data_google-csv', array($this, 'getTableData'), 10, 4);
        add_filter('ninja_tables_get_table_data_csv', array($this, 'getTableData'), 10, 4);
        add_filter('ninja_tables_fetching_table_rows_csv', array($this, 'data'), 10, 5);

        add_action('wp_ajax_ninja_table_external_data_source_create', array($this, 'createTableWithExternalDataSource'));

        add_filter('ninja_table_activated_features', function ($features) {
            $features['external_data_source'] = true;
            return $features;
        });

    }

    public function createTableWithExternalDataSource()
    {
        if(!current_user_can(ninja_table_admin_role())) {
            return;
        }

        $tableId = isset($_REQUEST['ID']) ? $_REQUEST['ID'] : null;
        $url = isset($_REQUEST['remoteURL']) ? $_REQUEST['remoteURL'] : $_REQUEST['remote_url'];

        $messages = array();
        // Validate Title
        if (!$tableId && empty($_REQUEST['post_title'])) {
            $messages['title'] = __('The title field is required.', 'ninja-tables');
        }

        // Validate URL
        if (empty($url) || !ninja_tables_is_valid_url($url)) {
            $messages['url'] = __('The url field is empty or invalid.', 'ninja-tables');
        }

        // If Validation failed
        if (array_filter($messages)) {
            wp_send_json_error(array('message' => $messages), 422);
            wp_die();
        }

        // Ensure the correct url if requesting goggle spreadsheet
        if (($type = $_REQUEST['type']) == 'google-csv') {
            $parsedUrl = parse_url($url);
            $path = substr($parsedUrl['path'], 0, strrpos($parsedUrl['path'], '/'));
            $url = $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . $path . '/pub?output=csv';
        }

        // For csv data type (google or other)
        if (in_array($type, array('csv', 'google-csv'))) {
            if (!empty($_REQUEST['get_headers_only'])) {
                // Make sure no error occured from wp_remote_get
                add_filter( 'https_ssl_verify', '__return_false' );
                $response = wp_remote_get($url);
                if (is_wp_error($response)) {
                    wp_send_json_error(array(
                        'message' => array(
                            'error' => __($response->get_error_message(), 'ninja-tables'),
                        )
                    ), 400);
                    wp_die();
                }

                $headers = $response['headers'];

                if (
                    strpos($headers['content-type'], 'csv') !== false ||
                    $headers['content-type'] == 'application/octet-stream' ||
                    $headers['content-type'] == 'application/binary'
                ) {
                    $headers = \League\Csv\Reader::createFromString(
                        $response['body']
                    )->fetchOne();

                    $formattedHeader = array();
                    foreach ($headers as $header) {
                        $formattedHeader[$header] = $header;
                    }
                    wp_send_json_success($formattedHeader);
                } else {
                    wp_send_json_error(array(
                        'message' => array(
                            'error' => __(
                                'Expected CSV but received invalid data type from the given url.',
                                'ninja-tables'
                            ),
                        )
                    ), 400);
                }
                wp_die();
            }


            $fields = array_map(function ($field) {
                return $field['name'];
            }, $_REQUEST['fields']);

            // Validate Fields
            if (empty($_REQUEST['fields'])) {
                $messages['fields'] = __('No fields were selected.', 'ninja-tables');
                if (array_filter($messages)) {
                    wp_send_json_error(array('message' => $messages), 422);
                    wp_die();
                }
            }

            $headers = ninja_table_format_header($fields);

            $columns = array();

            foreach ($headers as $key => $column) {
                $columns[] = array(
                    'name' => $column,
                    'key' => $key,
                    'breakpoints' => null,
                    'data_type' => 'text',
                    'dateFormat' => null,
                    'header_html_content' => null,
                    'enable_html_content' => false,
                    'contentAlign' => null,
                    'textAlign' => null,
                    'original_name' => $column
                );
            }


            if ($tableId) {
                $oldColumns = get_post_meta(
                    $tableId, '_ninja_table_columns', true
                );
                foreach ($columns as $key => $newColumn) {
                    foreach ($oldColumns as $oldColumn) {
                        if ($oldColumn['original_name'] == $newColumn['original_name']) {
                            $columns[$key] = $oldColumn;
                        }
                    }
                }
                // Reset/Reorder array indices
                $columns = array_values($columns);
            } else {
                $tableId = $this->saveTable();
                $tableSettings = ninja_table_get_table_settings($tableId, 'admin');
                $tableSettings['caching_interval'] = 5;
                update_post_meta($tableId, '_ninja_table_settings', $tableSettings);
            }
            update_post_meta($tableId, '_ninja_table_columns', $columns);
            update_post_meta($tableId, '_ninja_tables_data_provider', $type);
            update_post_meta($tableId, '_ninja_tables_data_provider_url', $url);

            wp_send_json_success(array('ID' => $tableId, 'remote_url' => $url));
        }
    }

    public function getTableSettings($table)
    {
        $table->isEditable = false;
        $table->dataSourceType = get_post_meta($table->ID, '_ninja_tables_data_provider', true);
        $table->remoteURL = get_post_meta($table->ID, '_ninja_tables_data_provider_url', true);
        $table->isEditableMessage = 'You may edit your table settings here.';
        $table->isExportable = true;
        $table->isImportable = false;
        $table->isSortable = false;
        $table->hasCacheFeature = false;
        $table->isCreatedSortable = false;
        $table->hasExternalCachingInterval = true;
        return $table;
    }

    public function getTableData($data, $tableId, $perPage, $offset)
    {
        $newData = array();

        $url = get_post_meta($tableId, '_ninja_tables_data_provider_url', true);
        $csvData = $this->getDataFromCsv($tableId, $url);
        if($csvData) {
            ninjaTableSetExternalCacheData($tableId, $csvData);
        }

        $totalData = count($csvData);

        $responseData = array_slice($csvData, $offset, $perPage);

        foreach ( $responseData as $key => $value) {
            $newData[] = array(
                'id' => $key + 1,
                'values' => $value,
                'position' => $key + 1,
            );
        }
        return array(
            $newData,
            $totalData
        );
    }

    public function data($data, $tableId, $defaultSorting, $limitEntries = false, $skip = false)
    {
        if(!$limitEntries && !$skip) {
            $cachedData = ninjaTableGetExternalCachedData($tableId);
            if ($cachedData) {
                return $cachedData;
            }
        }

        $url = get_post_meta($tableId, '_ninja_tables_data_provider_url', true);
        $csvData = $this->getDataFromCsv($tableId, $url);

        if($skip || $limitEntries) {
            $csvData = array_slice($csvData, $skip, $limitEntries);
        }

        if($csvData && !$limitEntries && !$skip) {
            ninjaTableSetExternalCacheData($tableId, $csvData);
        }

        return $url ? $csvData : $data;
    }

    protected function getDataFromCsv($tableId, $url)
    {
        $columns = array();
        foreach (ninja_table_get_table_columns($tableId) as $column) {
            $columns[$column['original_name']] = $column;
        }


        return array_map(function ($row) use ($columns) {
            $newRow = array();
            foreach ($columns as $key => $column) {
                $newRow[$column['key']] = $row[$key];
            }
            return $newRow;
        }, $this->csvToArray($url));
    }

    protected function csvToArray($url)
    {
        add_filter( 'https_ssl_verify', array($this, 'returnFalse') );
        $response = wp_remote_get($url);
        remove_filter( 'https_ssl_verify', array($this, 'returnFalse') );
        if (is_wp_error($response)) {
            return array();
        }
        if(!class_exists('\NinjaTables\Libs\CSVParser\CSVParser')) {
            return array();
        }
        $csvParser = new \NinjaTables\Libs\CSVParser\CSVParser();
        $csvParser->load_data($response['body']);
        $reader = $csvParser->parse($csvParser->find_delimiter());
        if($csvParser->error) {
           return array();
        }
        $data = array();
        $header = array_shift($reader);
        foreach ($reader as $row) {
            $data[] = array_combine($header, $row);
        }
        return $data;
    }

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

        if (!$postId) {
            $postId = wp_insert_post($attributes);
        } else {
            $attributes['ID'] = $postId;
            wp_update_post($attributes);
        }
        return $postId;
    }

    protected function get($array, $key, $default = false)
    {
        if (isset($array[$key])) {
            return $array[$key];
        }
        return $default;
    }

    public function returnFalse() {
        return false;
    }
}
