package com.printhub.printhub.utils.datatables;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Encapsula todos los parámetros que DataTables envía al backend
 * y los deja listos para usarlos en la capa de servicio / specification.
 */
public class DataTableRequest {

    /* ---------- sub-clase para la metadata de cada columna ---------- */
    public static class ColumnInfo {
        private final String name;
        private final boolean searchable;
        private final String filter;          // columns[i][search][value]

        public ColumnInfo(String name, boolean searchable, String filter) {
            this.name = name;
            this.searchable = searchable;
            this.filter = filter == null ? "" : filter;
        }

        public String getName()        { return name; }
        public boolean isSearchable()  { return searchable; }
        public String getFilter()      { return filter; }
    }

    /* ---------- campos principales ---------- */
    private final int draw;
    private final int start;
    private final int length;

    private final String globalSearch;
    private final List<ColumnInfo> columns;

    private final String orderColumn;      // nombre de la col a ordenar (o null)
    private final String orderDirection;   // asc / desc

    /* ---------- constructor: parsea los parámetros ---------- */
    public DataTableRequest(Map<String, String> params) {
        this.draw   = Integer.parseInt(params.getOrDefault("draw", "0"));
        this.start  = Integer.parseInt(params.getOrDefault("start", "0"));
        this.length = Integer.parseInt(params.getOrDefault("length", "10"));

        /* --- búsqueda global --- */
        this.globalSearch = params.getOrDefault("search[value]", "").trim();

        /* --- columnas --- */
        List<ColumnInfo> tmp = new ArrayList<>();
        int i = 0;
        while (params.containsKey("columns[" + i + "][data]")) {
            String name       = params.get("columns[" + i + "][data]");
            boolean searchable = Boolean.parseBoolean(params.getOrDefault(
                                   "columns[" + i + "][searchable]", "true"));
            String filter     = params.getOrDefault(
                                   "columns[" + i + "][search][value]", "");

            tmp.add(new ColumnInfo(name, searchable, filter.trim()));
            i++;
        }
        this.columns = Collections.unmodifiableList(tmp);

        /* --- orden --- */
        String ordIdx = params.get("order[0][column]");
        if (ordIdx != null) {
            int idx = Integer.parseInt(ordIdx);
            this.orderColumn    = (idx < columns.size()) ? columns.get(idx).getName() : null;
            this.orderDirection = params.getOrDefault("order[0][dir]", "asc");
        } else {
            this.orderColumn = null;
            this.orderDirection = "asc";
        }
    }

    /* ---------- getters / utilidades ---------- */
    public int getDraw()          { return draw; }
    public int getPage()          { return start / length; }
    public int getSize()          { return length; }

    public boolean hasOrder()     { return orderColumn != null; }
    public String getOrderColumn(){ return orderColumn; }
    public String getOrderDirection(){ return orderDirection; }

    public String getGlobalSearch() { return globalSearch; }

    /** Devuelve todas las columnas (incluyendo no-searchable) */
    public List<ColumnInfo> getColumns() { return columns; }

    /** Devuelve solo las columnas con searchable=true */
    public List<ColumnInfo> getSearchableColumns() {
        return columns.stream()
                      .filter(ColumnInfo::isSearchable)
                      .toList();
    }

    /** Obtiene el filtro individual para una columna por nombre */
    public String getColumnFilter(String columnName) {
        return columns.stream()
                      .filter(c -> c.getName().equals(columnName))
                      .map(ColumnInfo::getFilter)
                      .findFirst()
                      .orElse("");
    }
}
