package ai.decompile.job.model.specification;

import ai.decompile.job.model.entity.Job;
import ai.decompile.job.model.enums.JobStatus;
import ai.decompile.job.model.enums.JobType;
import jakarta.persistence.criteria.JoinType;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.data.jpa.domain.Specification;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JobSpecification {
  public static Specification<Job> withFilters(
      UUID projectId, JobStatus status, JobType type, String search) {
    Specification<Job> spec = (_, _, cb) -> cb.conjunction();

    if (projectId != null) {
      spec = spec.and(hasProjectId(projectId));
    }

    if (status != null) {
      spec = spec.and(hasStatus(status));
    }

    if (type != null) {
      spec = spec.and(hasType(type));
    }

    if (search != null && !search.isBlank()) {
      spec = spec.and(binaryOrProjectNameContains(search));
    }

    return spec;
  }

  public static Specification<Job> hasProjectId(UUID projectId) {
    return (root, _, cb) -> cb.equal(root.get("projectId"), projectId);
  }

  public static Specification<Job> hasStatus(JobStatus status) {
    return (root, _, cb) -> cb.equal(root.get("status"), status);
  }

  public static Specification<Job> hasType(JobType type) {
    return (root, _, cb) -> cb.equal(root.get("type"), type);
  }

  public static Specification<Job> binaryOrProjectNameContains(String search) {
    String pattern = "%" + search.toLowerCase() + "%";
    return (root, _, cb) -> {
      var binary = root.join("binary", JoinType.LEFT);
      var project = root.join("project", JoinType.LEFT);
      return cb.or(
          cb.like(cb.lower(binary.get("filename")), pattern),
          cb.like(cb.lower(project.get("name")), pattern));
    };
  }
}
