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

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.training.model.dto.ModelTrainMngDto;
import com.kamco.cd.training.postgres.core.ModelTrainJobCoreService;
import com.kamco.cd.training.postgres.core.ModelTrainMngCoreService;
import com.kamco.cd.training.train.dto.ModelTrainJobQueuedEvent;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class TestJobService {
  private final ModelTrainJobCoreService modelTrainJobCoreService;
  private final ModelTrainMngCoreService modelTrainMngCoreService;
  private final DockerTrainService dockerTrainService;
  private final ObjectMapper objectMapper;
  private final ApplicationEventPublisher eventPublisher;

  @Transactional
  public Long enqueue(Long modelId, UUID uuid, int epoch) {

    // 마스터 확인
    modelTrainMngCoreService.findModelById(modelId);

    // best epoch 업데이트
    modelTrainMngCoreService.updateModelMasterBestEpoch(modelId, epoch);

    Map<String, Object> params = new java.util.LinkedHashMap<>();
    params.put("jobType", "EVAL");
    params.put("uuid", String.valueOf(uuid));
    params.put("epoch", epoch);

    int nextAttemptNo = modelTrainJobCoreService.findMaxAttemptNo(modelId) + 1;

    Long jobId =
        modelTrainJobCoreService.createQueuedJob(
            modelId, nextAttemptNo, params, ZonedDateTime.now());

    // step2 시작으로 마킹
    modelTrainMngCoreService.markStep2InProgress(modelId, jobId);

    eventPublisher.publishEvent(new ModelTrainJobQueuedEvent(jobId));
    return jobId;
  }

  @Transactional
  public void cancel(Long modelId) {

    ModelTrainMngDto.Basic master = modelTrainMngCoreService.findModelById(modelId);

    Long jobId = master.getCurrentAttemptId();
    if (jobId == null) {
      throw new IllegalStateException("실행중인 작업이 없습니다.");
    }

    var job =
        modelTrainJobCoreService
            .findById(jobId)
            .orElseThrow(() -> new IllegalStateException("Job not found"));

    String containerName = job.getContainerName();

    // 1) 컨테이너 강제 종료 + 제거 (없거나 이미 죽었어도 괜찮게)
    if (containerName != null && !containerName.isBlank()) {
      dockerTrainService.killContainer(containerName);
    }

    // 2) 상태 업데이트 (항상 수행)
    modelTrainJobCoreService.markCanceled(jobId);
    modelTrainMngCoreService.markStopped(modelId);
  }
}
