package com.kamco.cd.training.train.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.nio.file.Path;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

public class ModelTrainMetricsDto {

  @Schema(name = "ResponsePathDto", description = "AI 결과 저장된 path 경로 정보")
  @Getter
  @Setter
  @NoArgsConstructor
  @AllArgsConstructor
  public static class ResponsePathDto {

    private Long modelId;
    private String responsePath;
    private UUID uuid;
  }

  @Schema(name = "BestPthInfo", description = "Best PTH 파일 정보")
  @Getter
  @AllArgsConstructor
  public static class BestPthInfo {

    private String fileName; // best_changed_fscore_epoch_3.pth
    private String metricType; // fscore, precision, recall
    private Integer epoch; // 3
    private Path filePath; // 파일 전체 경로
  }

  @Getter
  @AllArgsConstructor
  public static class ModelMetricJsonDto {

    @JsonProperty("cd_model_type")
    private String cdModelType;

    @JsonProperty("model_version")
    private String modelVersion;

    @JsonProperty("metric_type")
    private String metricType; // fscore, precision, recall

    private Integer epoch; // epoch 번호

    private Properties properties;

    @JsonProperty("test_metrics")
    private TestMetrics testMetrics; // 테스트 메트릭 추가

    // 기존 방식용 생성자 (metricType, epoch, testMetrics 없음)
    public ModelMetricJsonDto(String cdModelType, String modelVersion, Properties properties) {
      this.cdModelType = cdModelType;
      this.modelVersion = modelVersion;
      this.metricType = null;
      this.epoch = null;
      this.properties = properties;
      this.testMetrics = null;
    }
  }

  @Getter
  @AllArgsConstructor
  @NoArgsConstructor
  public static class TestMetrics {

    private String model; // 모델명

    @JsonProperty("true_positive")
    private Long tp; // True Positive

    @JsonProperty("false_positive")
    private Long fp; // False Positive

    @JsonProperty("false_negative")
    private Long fn; // False Negative

    private Float precisions; // Precision

    private Float recall; // Recall

    @JsonProperty("f1_score")
    private Float f1Score; // F1 Score

    private Float accuracy; // Accuracy

    private Float iou; // IoU

    @JsonProperty("detection_count")
    private Long detectionCount; // Detection Count

    @JsonProperty("gt_count")
    private Long gtCount; // Ground Truth Count
  }

  @Getter
  @AllArgsConstructor
  public static class Properties {

    // 변화 탐지 관련 메트릭 (Changed)
    @JsonProperty("changed_fscore")
    private Float changedFscore;

    @JsonProperty("changed_precision")
    private Float changedPrecision;

    @JsonProperty("changed_recall")
    private Float changedRecall;

    // 비변화 관련 메트릭 (Unchanged)
    @JsonProperty("unchanged_fscore")
    private Float unchangedFscore;

    @JsonProperty("unchanged_precision")
    private Float unchangedPrecision;

    @JsonProperty("unchanged_recall")
    private Float unchangedRecall;

    // 평균 메트릭 (Mean)
    @JsonProperty("mean_fscore")
    private Float mFscore;

    @JsonProperty("mean_precision")
    private Float mPrecision;

    @JsonProperty("mean_recall")
    private Float mRecall;

    @JsonProperty("mean_iou")
    private Float mIou;

    @JsonProperty("mean_accuracy")
    private Float mAcc;

    // 전체 정확도 (Overall Accuracy)
    @JsonProperty("overall_accuracy")
    private Float aAcc;

    // 학습 관련 메트릭
    @JsonProperty("loss")
    private Double loss;

    @JsonProperty("learning_rate")
    private Double lr;

    @JsonProperty("duration_time")
    private Float durationTime;

    // 기존 방식용 생성자 (getTestMetricPackingInfo에서 사용)
    public Properties(Float f1Score, Float precisions, Float recall, Float iou, Double loss) {
      this.changedFscore = f1Score;
      this.changedPrecision = precisions;
      this.changedRecall = recall;
      this.unchangedFscore = null;
      this.unchangedPrecision = null;
      this.unchangedRecall = null;
      this.mFscore = null;
      this.mPrecision = null;
      this.mRecall = null;
      this.mIou = iou;
      this.mAcc = null;
      this.aAcc = null;
      this.loss = loss;
      this.lr = null;
      this.durationTime = null;
    }
  }

  @Getter
  @AllArgsConstructor
  public static class ModelTestFileName {

    private String bestEpochFileName;
    private String modelVersion;
  }

  /** 간단한 JSON 형식용 DTO (ZIP 파일 포함용) */
  @Getter
  @AllArgsConstructor
  public static class SimpleMetricJsonDto {

    @JsonProperty("cd_model_type")
    private String cdModelType;

    @JsonProperty("model_version")
    private String modelVersion;

    private SimpleProperties properties;
  }

  /** 간단한 Properties (필수 메트릭만 포함) */
  @Getter
  @AllArgsConstructor
  public static class SimpleProperties {

    @JsonProperty("f1_score")
    private Float f1Score;

    private Float precision;

    private Float recall;

    private Float iou;

    private Double loss;
  }
}
