package com.printhub.printhub.specification.configuration;

import com.printhub.printhub.model.configuration.Printer;
import com.printhub.printhub.utils.datatables.DataTableRequest;

import org.springframework.data.jpa.domain.Specification;

import jakarta.persistence.criteria.Path;

import jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

public class PrinterSpecification {

    public static Specification<Printer> filterBy(String name) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (name != null && !name.isBlank()) {
                predicates.add(cb.like(cb.lower(root.get("name")), "%" + name.toLowerCase() + "%"));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }

    public static Specification<Printer> buildSpec(DataTableRequest dt) {
        return (root, query, cb) -> {
            List<Predicate> ands = new ArrayList<>();

            /* --------------- 1. Búsqueda global ---------------- */
            if (!dt.getGlobalSearch().isBlank()) {
                String term = "%" + dt.getGlobalSearch().toLowerCase() + "%";

                // OR sobre todas las columnas marcadas como searchable=true
                List<Predicate> ors = new ArrayList<>();
                for (var col : dt.getSearchableColumns()) {
                    Path<?> path = root.get(col.getName());

                    if (path.getJavaType().equals(String.class)) {
                        ors.add(cb.like(cb.lower(path.as(String.class)), term));
                    }
                    // si quisieras buscar por id cuando el globalSearch es numérico:
                    else if (path.getJavaType().equals(Long.class)) {
                        try {
                            Long value = Long.valueOf(dt.getGlobalSearch());
                            ors.add(cb.equal(path, value));
                        } catch (NumberFormatException ignored) {
                            /* el término no es número */ }
                    }
                }

                // si hay columnas OR, añádelo al AND general
                if (!ors.isEmpty()) {
                    ands.add(cb.or(ors.toArray(new Predicate[0])));
                }
            }

            /* --------------- 2. Filtros individuales ------------ */
            for (var col : dt.getColumns()) {
                if (!col.getFilter().isBlank()) {
                    ands.add(cb.like(cb.lower(root.get(col.getName())),
                            "%" + col.getFilter().toLowerCase() + "%"));
                }
            }

            /* --------------- 3. Resultado ---------------------- */
            return ands.isEmpty()
                    ? cb.conjunction() // sin filtros
                    : cb.and(ands.toArray(new Predicate[0]));
        };
    }

}
