package io.synor.compute;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * Result of a compute job execution.
 *
 * @param <T> Type of the result data
 */
@JsonIgnoreProperties(ignoreUnknown = true)
public class JobResult<T> {
    @JsonProperty("job_id")
    private String jobId;

    @JsonProperty("status")
    private JobStatus status;

    @JsonProperty("result")
    private T result;

    @JsonProperty("error")
    private String error;

    @JsonProperty("execution_time_ms")
    private Long executionTimeMs;

    @JsonProperty("processor")
    private ProcessorType processor;

    @JsonProperty("cost")
    private Double cost;

    // Default constructor for Jackson
    public JobResult() {}

    public JobResult(String jobId, JobStatus status, T result, String error,
                     Long executionTimeMs, ProcessorType processor, Double cost) {
        this.jobId = jobId;
        this.status = status;
        this.result = result;
        this.error = error;
        this.executionTimeMs = executionTimeMs;
        this.processor = processor;
        this.cost = cost;
    }

    public String getJobId() {
        return jobId;
    }

    public JobStatus getStatus() {
        return status;
    }

    public T getResult() {
        return result;
    }

    public String getError() {
        return error;
    }

    public Long getExecutionTimeMs() {
        return executionTimeMs;
    }

    public ProcessorType getProcessor() {
        return processor;
    }

    public Double getCost() {
        return cost;
    }

    /**
     * Check if the job completed successfully.
     */
    public boolean isSuccess() {
        return status == JobStatus.COMPLETED && error == null;
    }

    /**
     * Check if the job failed.
     */
    public boolean isFailed() {
        return status == JobStatus.FAILED || error != null;
    }

    /**
     * Create a successful result.
     */
    public static <T> JobResult<T> success(String jobId, T result, Long executionTimeMs,
                                            ProcessorType processor, Double cost) {
        return new JobResult<>(jobId, JobStatus.COMPLETED, result, null,
                               executionTimeMs, processor, cost);
    }

    /**
     * Create a failed result.
     */
    public static <T> JobResult<T> failure(String jobId, String error) {
        return new JobResult<>(jobId, JobStatus.FAILED, null, error, null, null, null);
    }

    @Override
    public String toString() {
        return "JobResult{" +
               "jobId='" + jobId + '\'' +
               ", status=" + status +
               ", result=" + (result != null ? result.getClass().getSimpleName() : "null") +
               ", error='" + error + '\'' +
               ", executionTimeMs=" + executionTimeMs +
               ", processor=" + processor +
               ", cost=" + cost +
               '}';
    }
}
