package at.procon.dip.clustering.dto;

import at.procon.dip.clustering.ClusteringAlgorithm;
import at.procon.dip.clustering.ClusteringExecutionBackend;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.Valid;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.LinkedHashMap;
import java.util.Map;

public record CreateClusterRunRequest(
        String clusterSetCode,
        @NotBlank String name,
        @NotNull ClusteringAlgorithm algorithm,
        ClusteringExecutionBackend executionBackend,
        @Valid ReductionConfig reduction,
        @Valid @NotNull EmbeddingSelectionSpec selection,
        Integer k,
        Map<String, Object> parameters
) {

    @JsonIgnore
    public Map<String, Object> resolvedParameters() {
        Map<String, Object> merged = new LinkedHashMap<>();
        if (parameters != null) {
            merged.putAll(parameters);
        }
        if (k != null && !merged.containsKey("k")) {
            merged.put("k", k);
        }
        return merged;
    }

    @AssertTrue(message = "k must be > 0 for KMEANS and MINI_BATCH_KMEANS; for other algorithms it must be omitted or > 0")
    @JsonIgnore
    public boolean isValidKConfiguration() {
        Integer effectiveK = extractPositiveInteger(resolvedParameters().get("k"));

        if (algorithm == ClusteringAlgorithm.KMEANS
                || algorithm == ClusteringAlgorithm.MINI_BATCH_KMEANS) {
            return effectiveK != null;
        }

        Object rawK = resolvedParameters().get("k");
        return rawK == null || effectiveK != null;
    }

    private Integer extractPositiveInteger(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof Number number) {
            int intValue = number.intValue();
            return intValue > 0 ? intValue : null;
        }
        try {
            int intValue = Integer.parseInt(String.valueOf(value));
            return intValue > 0 ? intValue : null;
        } catch (NumberFormatException ex) {
            return null;
        }
    }
}
