<?php

namespace NinjaTablesPro\App\Modules\DataTables\Handlers;

use NinjaTables\App\Modules\DataTables\Database\DynamicTableManager;
use NinjaTables\App\Modules\DataTables\Models\DynamicRow;

class SortableHandler
{
    public static function init($tableId, $tableSettings, $requestData)
    {
        // Update the table's sorting settings
        $tableSettings['sorting_type'] = 'manual_sort';
        update_post_meta($tableId, '_ninja_table_settings', $tableSettings);

        if (isset($requestData['noData'])) {
            return;
        }

        // Use the DataTables DynamicRow model
        $dynamicRow = new DynamicRow($tableId);

        if (!$dynamicRow->tableExists()) {
            wp_send_json([
                'total'        => 0,
                'per_page'     => 20,
                'current_page' => 1,
                'last_page'    => 0,
                'data'         => [],
                'data_source'  => 'datatables',
            ], 200);

            return;
        }

        $perPage        = isset($requestData['per_page']) ? intval($requestData['per_page']) : 10;
        $currentPage    = isset($requestData['page']) ? intval($requestData['page']) : 1;
        $search         = isset($requestData['search']) ? sanitize_text_field($requestData['search']) : '';
        $defaultSorting = isset($tableSettings['default_sorting']) ? $tableSettings['default_sorting'] : 'old_first';

        // For manual sorting, always order by position
        $orderBy = DynamicTableManager::COL_POSITION;
        $order   = ($defaultSorting === 'new_first') ? 'DESC' : 'ASC';

        $rows  = $dynamicRow->getAll($perPage, $currentPage, $orderBy, $order, $search ?: null);
        $total = $dynamicRow->count($search ?: null);

        $formattedRows = [];
        foreach ($rows as $row) {
            $formattedRows[] = self::formatRow($dynamicRow->mapRowToUserKeys($row));
        }

        wp_send_json([
            'total'        => $total,
            'per_page'     => $perPage,
            'current_page' => $currentPage,
            'last_page'    => $total > 0 ? ceil($total / $perPage) : 0,
            'data'         => $formattedRows,
            'data_source'  => 'datatables',
        ], 200);
    }

    public static function store($tableId, $rowId, $newPosition, $requestData)
    {
        global $wpdb;

        $dynamicRow   = new DynamicRow($tableId);
        $tableManager = $dynamicRow->getTableManager();
        $tableName    = $tableManager->getTableName();

        if (!$dynamicRow->tableExists()) {
            return [
                'success' => false,
                'message' => __('Dynamic table does not exist.', 'ninja-tables-pro'),
            ];
        }

        // Get current row
        $currentRow = $dynamicRow->find($rowId);
        if (!$currentRow) {
            return [
                'success' => false,
                'message' => __('Row not found.', 'ninja-tables-pro'),
            ];
        }

        $colId       = DynamicTableManager::COL_ID;
        $colPosition = DynamicTableManager::COL_POSITION;

        $oldPosition = $currentRow->{$colPosition};
        $total       = $dynamicRow->count();

        // Clamp newPosition to valid range
        $newPosition = max(1, min($newPosition, $total));

        // No-op if position hasn't changed
        if ($newPosition === $oldPosition) {
            return [
                'success' => true,
                'message' => __('Position unchanged.', 'ninja-tables-pro'),
            ];
        }

        // Temporarily set position to 0 so it doesn't interfere with reordering
        $wpdb->update($tableName, [$colPosition => 0], [$colId => $rowId]);

        // Reorder positions
        if ($newPosition < $oldPosition) {
            $wpdb->query(
                $wpdb->prepare(
                    "UPDATE {$tableName}
                 SET `{$colPosition}` = `{$colPosition}` + 1
                 WHERE `{$colPosition}` >= %d AND `{$colPosition}` < %d
                 ORDER BY `{$colPosition}` DESC",
                    $newPosition,
                    $oldPosition
                )
            );
        } else {
            $wpdb->query(
                $wpdb->prepare(
                    "UPDATE {$tableName}
                 SET `{$colPosition}` = `{$colPosition}` - 1
                 WHERE `{$colPosition}` > %d AND `{$colPosition}` <= %d
                 ORDER BY `{$colPosition}` ASC",
                    $oldPosition,
                    $newPosition
                )
            );
        }

        // Update the moved row's final position; restore old position on failure
        $updated = $wpdb->update($tableName, [$colPosition => $newPosition], [$colId => $rowId]);

        if ($updated === false) {
            $wpdb->update($tableName, [$colPosition => $oldPosition], [$colId => $rowId]);

            return [
                'success' => false,
                'message' => __('Failed to update row position.', 'ninja-tables-pro'),
            ];
        }

        // Clear cache
        ninjaTablesClearTableDataCache($tableId);

        // Return updated data
        $tableSettings  = ninja_table_get_table_settings($tableId, 'admin');
        $perPage        = isset($requestData['per_page']) ? intval($requestData['per_page']) : 10;
        $currentPage    = isset($requestData['page']) ? intval($requestData['page']) : 1;
        $search         = isset($requestData['search']) ? sanitize_text_field($requestData['search']) : '';
        $defaultSorting = isset($tableSettings['default_sorting']) ? $tableSettings['default_sorting'] : 'old_first';

        $orderBy = DynamicTableManager::COL_POSITION;
        $order   = ($defaultSorting === 'new_first') ? 'DESC' : 'ASC';

        $rows  = $dynamicRow->getAll($perPage, $currentPage, $orderBy, $order, $search ?: null);
        $total = $dynamicRow->count($search ?: null);

        $formattedRows = [];
        foreach ($rows as $row) {
            $formattedRows[] = self::formatRow($dynamicRow->mapRowToUserKeys($row));
        }

        return [
            'success'      => true,
            'total'        => $total,
            'per_page'     => $perPage,
            'current_page' => $currentPage,
            'last_page'    => $total > 0 ? ceil($total / $perPage) : 0,
            'data'         => $formattedRows,
            'data_source'  => 'datatables',
        ];
    }

    protected static function formatRow($row)
    {
        return [
            'id'         => $row['id'],
            'position'   => $row['position'],
            'values'     => $row['values'],
            'settings'   => $row['settings'],
            'created_by' => $row['owner_id'],
            'created_at' => $row['created_at'],
            'updated_at' => $row['updated_at'],
        ];
    }
}
