package com.kamco.cd.training.postgres.core;

import com.kamco.cd.training.postgres.entity.ModelTrainJobEntity;
import com.kamco.cd.training.postgres.repository.train.ModelTrainJobRepository;
import com.kamco.cd.training.train.dto.ModelTrainJobDto;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ModelTrainJobCoreService {

  private final ModelTrainJobRepository modelTrainJobRepository;

  public int findMaxAttemptNo(Long modelId) {
    return modelTrainJobRepository.findMaxAttemptNo(modelId);
  }

  public Optional<ModelTrainJobDto> findLatestByModelId(Long modelId) {
    return modelTrainJobRepository.findLatestByModelId(modelId).map(ModelTrainJobEntity::toDto);
  }

  public Optional<ModelTrainJobDto> findById(Long jobId) {
    return modelTrainJobRepository.findById(jobId).map(ModelTrainJobEntity::toDto);
  }

  /** QUEUED Job 생성 */
  @Transactional
  public Long createQueuedJob(
      Long modelId, int attemptNo, Map<String, Object> paramsJson, ZonedDateTime queuedDttm) {

    ModelTrainJobEntity job = new ModelTrainJobEntity();
    job.setModelId(modelId);
    job.setAttemptNo(attemptNo);
    job.setStatusCd("QUEUED");
    job.setParamsJson(paramsJson);
    job.setQueuedDttm(queuedDttm != null ? queuedDttm : ZonedDateTime.now());

    modelTrainJobRepository.save(job);
    return job.getId();
  }

  /** 실행 시작 처리 */
  @Transactional
  public void markRunning(
      Long jobId, String containerName, String logPath, String lockedBy, Integer totalEpoch) {
    ModelTrainJobEntity job =
        modelTrainJobRepository
            .findById(jobId)
            .orElseThrow(() -> new IllegalArgumentException("Job not found: " + jobId));

    job.setStatusCd("RUNNING");
    job.setContainerName(containerName);
    job.setLogPath(logPath);
    job.setStartedDttm(ZonedDateTime.now());
    job.setLockedDttm(ZonedDateTime.now());
    job.setLockedBy(lockedBy);

    if (totalEpoch != null) {
      job.setTotalEpoch(totalEpoch);
    }
  }

  /** 성공 처리 */
  @Transactional
  public void markSuccess(Long jobId, int exitCode) {
    ModelTrainJobEntity job =
        modelTrainJobRepository
            .findById(jobId)
            .orElseThrow(() -> new IllegalArgumentException("Job not found: " + jobId));

    job.setStatusCd("SUCCESS");
    job.setExitCode(exitCode);
    job.setFinishedDttm(ZonedDateTime.now());
  }

  /** 실패 처리 */
  @Transactional
  public void markFailed(Long jobId, Integer exitCode, String errorMessage) {
    ModelTrainJobEntity job =
        modelTrainJobRepository
            .findById(jobId)
            .orElseThrow(() -> new IllegalArgumentException("Job not found: " + jobId));

    job.setStatusCd("FAILED");
    job.setExitCode(exitCode);
    job.setErrorMessage(errorMessage);
    job.setFinishedDttm(ZonedDateTime.now());
  }

  /** 취소 처리 */
  @Transactional
  public void markCanceled(Long jobId) {
    ModelTrainJobEntity job =
        modelTrainJobRepository
            .findById(jobId)
            .orElseThrow(() -> new IllegalArgumentException("Job not found: " + jobId));

    job.setStatusCd("STOPPED");
    job.setFinishedDttm(ZonedDateTime.now());
  }
}
