<?php

namespace NinjaTablesPro\App\Http\Controllers;

use NinjaTables\App\Models\NinjaTableItem as TableItem;
use NinjaTables\Framework\Request\Request;
use NinjaTablesPro\App\Models\NinjaTableItem;
use NinjaTablesPro\App\Traits\SortableTrait;
use NinjaTablesPro\App\Modules\DataTables\Handlers\SortableHandler;

class SortableController extends Controller
{
    use SortableTrait;

    public function init(Request $request)
    {
        global $wpdb;

        $tableId        = intval($request->getSafe('table_id'));
        $dataSourceType = ninja_table_get_data_provider($tableId);
        $tableSettings  = ninja_table_get_table_settings($tableId, 'admin');

        // Dispatch to DataTables handler if using DataTables rendering engine
        $library = isset($tableSettings['library']) ? $tableSettings['library'] : 'footable';
        if ($library === 'datatables') {
            SortableHandler::init($tableId, $tableSettings, $_REQUEST);

            return;
        }

        $tableName = $wpdb->prefix . static::$tableName;

        static::migrateDatabaseIfNeeded($tableName);

        // The post meta table would have a flag that the data of
        // the table is migrated to use for the manual sorting.
        $dataMigrated = ninjaTablesDataMigratedForManualSort($tableId);

        if (!$dataMigrated) {
            $orderBy = ($tableSettings['default_sorting'] === 'old_first') ? 'ASC' : 'DESC';

            // Initialize the `position` value of the data to allow manual sort.
            $wpdb->query("SET @p=0");

            $wpdb->query($wpdb->prepare(
                "UPDATE {$tableName} SET position = @p := (@p+1) WHERE table_id = %d ORDER BY created_at {$orderBy}",
                $tableId
            ));

            // Update the post meta table that the data of this
            // table is migrated to use for manual sorting.
            $postMetaKey = '_ninja_tables_data_migrated_for_manual_sort';
            update_post_meta($tableId, $postMetaKey, true);
        } else {
            static::recheckItemPositions($tableId);
        }

        // Finally update the table's sorting settings.
        $tableSettings['sorting_type'] = 'manual_sort';
        update_post_meta($tableId, '_ninja_table_settings', $tableSettings);

        if (!isset($_REQUEST['noData'])) {
            $perPage     = isset($_REQUEST['per_page']) ? intval($_REQUEST['per_page']) : 10;
            $currentPage = isset($_REQUEST['page']) ? intval($_REQUEST['page']) : 1;
            $skip        = $perPage * ($currentPage - 1);
            $search      = $request->getSafe('search', 'sanitize_text_field', '');
            $data        = TableItem::getItems($tableId, $perPage, $currentPage, $skip, $search, $dataSourceType);

            wp_send_json($data, 200);
        }
    }

    public function store(Request $request)
    {
        global $wpdb;

        $id             = $request->getSafe('id', 'intval');
        $tableId        = $request->getSafe('table_id', 'intval');
        $newPosition    = $request->getSafe('newPosition', 'intval');
        $dataSourceType = ninja_table_get_data_provider($tableId);

        // Dispatch to DataTables handler if using DataTables rendering engine
        $tableSettings = ninja_table_get_table_settings($tableId, 'admin');
        $library       = isset($tableSettings['library']) ? $tableSettings['library'] : 'footable';
        if ($library === 'datatables') {
            $result = SortableHandler::store($tableId, $id, $newPosition, $_REQUEST);

            if (!$result['success']) {
                return $this->json(['message' => $result['message']], 400);
            }

            unset($result['success']);

            return $this->json($result, 200);
        }

        $tableName   = $wpdb->prefix . static::$tableName;
        $oldPosition = NinjaTableItem::where('table_id', $tableId)->where('id', $id)->first()->position;

        // Initially make the target item's position `0`, so that
        // it doesn't get in the way of later sql queries.
        NinjaTableItem::where('table_id', $tableId)->where('id', $id)->update(['position' => 0]);

        // If the new position where the item is to be moved
        // is less than its old position we'll increment
        // each item's position that falls between new
        // position and old position by 1
        if ($newPosition < $oldPosition) {
            $query = "UPDATE {$tableName}
                      SET position = position + 1
                      WHERE table_id = %d
                      AND position BETWEEN %d AND %d
                      ORDER BY position DESC";

            $bindings = array(
                $tableId,
                $newPosition,
                $oldPosition,
            );
        }

        // If the new position where the item is to be moved
        // is greater than its old position we'll decrement
        // each item's position that falls between old
        // position and new position by 1
        elseif ($newPosition > $oldPosition) {
            $query = "UPDATE {$tableName}
                      SET position = position - 1
                      WHERE table_id = %d
                      AND position BETWEEN %d AND %d
                      ORDER BY position ASC";

            $bindings = [
                $tableId,
                $oldPosition,
                $newPosition,
            ];
        }

        // Run the prepared query to batch update the
        // items that matches the sorting conditions.
        $wpdb->query($wpdb->prepare($query, $bindings));

        // Finally update the target item's position value with its intended position.
        NinjaTableItem::where('table_id', $tableId)->where('id', $id)->update(['position' => $newPosition]);
        ninjaTablesClearTableDataCache($tableId);
        // Now return the data.

        $perPage     = isset($_REQUEST['per_page']) ? intval($_REQUEST['per_page']) : 10;
        $currentPage = isset($_REQUEST['page']) ? intval($_REQUEST['page']) : 1;
        $skip        = $perPage * ($currentPage - 1);
        $search      = $request->getSafe('search', 'sanitize_text_field', '');
        $data        = TableItem::getItems($tableId, $perPage, $currentPage, $skip, $search, $dataSourceType);

        return $this->json($data, 200);
    }
}
