package com.imprimelibros.erp.datatables;

import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import java.util.ArrayList;
import java.util.List;

public class DataTablesService {

    public static <T> DataTablesResponse<T> handle(
            DataTablesRequest dt,
            JpaSpecificationExecutor<T> repo,
            long totalCount, // count sin filtros (cacheable)
            List<String> searchableFields,
            Class<T> entityClass) {
        // Spec (filtros)
        Specification<T> spec = DataTablesSpecification.build(dt, searchableFields);

        // Sort
        Sort sort = Sort.unsorted();
        if (!dt.order.isEmpty() && !dt.columns.isEmpty()) {
            List<Sort.Order> orders = new ArrayList<>();
            for (var o : dt.order) {
                var col = dt.columns.get(o.column);
                String field = col != null ? col.name : null;

                // Acepta solo columnas válidas: no vacías, marcadas como orderable y en la
                // whitelist "searchable"
                if (field == null || field.isBlank())
                    continue;
                if (!col.orderable)
                    continue;
                if (!searchableFields.contains(field))
                    continue;

                orders.add(new Sort.Order(
                        "desc".equalsIgnoreCase(o.dir) ? Sort.Direction.DESC : Sort.Direction.ASC,
                        field));
            }
            if (!orders.isEmpty()) {
                sort = Sort.by(orders);
            } else {
                // Fallback: primera columna de dt.columns que sea orderable y esté en la
                // whitelist
                for (var c : dt.columns) {
                    if (c != null && c.orderable && c.name != null && !c.name.isBlank()
                            && searchableFields.contains(c.name)) {
                        sort = Sort.by(c.name);
                        break;
                    }
                }
                // Si no hay ninguna válida, sort se queda UNSORTED
            }
        }

        // Page
        int page = dt.length > 0 ? dt.start / dt.length : 0;
        Pageable pageable = dt.length > 0 ? PageRequest.of(page, dt.length, sort) : Pageable.unpaged();

        // Query
        Page<T> result = repo.findAll(spec, pageable);
        long filtered = result.getTotalElements();

        return new DataTablesResponse<>(
                dt.draw,
                totalCount,
                filtered,
                result.getContent());
    }
}
