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

import com.kamco.cd.training.common.enums.LearnDataRegister;
import com.kamco.cd.training.common.enums.LearnDataType;
import com.kamco.cd.training.common.exception.NotFoundException;
import com.kamco.cd.training.common.service.BaseCoreService;
import com.kamco.cd.training.dataset.dto.DatasetClsObjDto;
import com.kamco.cd.training.dataset.dto.DatasetDto;
import com.kamco.cd.training.dataset.dto.DatasetDto.DatasetMngRegDto;
import com.kamco.cd.training.dataset.dto.DatasetObjDto;
import com.kamco.cd.training.dataset.dto.DatasetObjDto.DatasetClass;
import com.kamco.cd.training.dataset.dto.DatasetObjDto.DatasetObjRegDto;
import com.kamco.cd.training.postgres.entity.DatasetClsObjEntity;
import com.kamco.cd.training.postgres.entity.DatasetEntity;
import com.kamco.cd.training.postgres.entity.DatasetObjEntity;
import com.kamco.cd.training.postgres.repository.dataset.DatasetClsRepository;
import com.kamco.cd.training.postgres.repository.dataset.DatasetObjRepository;
import jakarta.transaction.Transactional;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
@Slf4j
public class DatasetClsCoreService
    implements BaseCoreService<DatasetDto.Basic, Long, DatasetDto.SearchReq> {

  private final DatasetClsRepository datasetClsRepository;
  private final DatasetObjRepository datasetObjRepository;

  /**
   * 학습 데이터 삭제
   *
   * @param id 데이터셋 ID
   */
  @Override
  public void remove(Long id) {
    DatasetEntity entity =
        datasetClsRepository
            .findById(id)
            .orElseThrow(() -> new NotFoundException("데이터셋을 찾을 수 없습니다. ID: " + id));
    entity.setDeleted(true);
    datasetClsRepository.save(entity);
  }

  public void remove(UUID id) {
    DatasetEntity entity =
        datasetClsRepository
            .findByUuid(id)
            .orElseThrow(() -> new NotFoundException("데이터셋을 찾을 수 없습니다. ID: " + id));
    entity.setDeleted(true);
    datasetClsRepository.save(entity);
  }

  @Override
  public DatasetDto.Basic getOneById(Long id) {
    DatasetEntity entity =
        datasetClsRepository
            .findById(id)
            .orElseThrow(() -> new NotFoundException("데이터셋을 찾을 수 없습니다. ID: " + id));

    if (entity.getDeleted()) {
      throw new NotFoundException("삭제된 데이터셋입니다. ID: " + id);
    }

    return entity.toDto();
  }

  public DatasetDto.Basic getOneByUuid(UUID id) {
    DatasetEntity entity =
        datasetClsRepository
            .findByUuid(id)
            .orElseThrow(() -> new NotFoundException("데이터셋을 찾을 수 없습니다. uuid: " + id));
    return entity.toDto();
  }

  @Override
  public Page<DatasetDto.Basic> search(DatasetDto.SearchReq searchReq) {
    Page<DatasetEntity> entityPage = datasetClsRepository.findDatasetList(searchReq);
    return entityPage.map(DatasetEntity::toDto);
  }

  /**
   * 학습데이터 조회
   *
   * @param searchReq 검색 조건
   * @return 페이징 처리된 데이터셋 목록
   */
  public Page<DatasetDto.Basic> findDatasetList(DatasetDto.SearchReq searchReq) {
    return search(searchReq);
  }

  // TODO 미사용시작
  /**
   * 학습데이터 등록
   *
   * @param registerReq 등록 요청 데이터
   * @return 등록된 데이터셋 정보
   */
  public DatasetDto.Basic save(DatasetDto.RegisterReq registerReq) {
    // 먼저 id1 필드를 임시값(0)으로 설정하여 저장
    DatasetEntity entity = new DatasetEntity();
    entity.setTitle(registerReq.getTitle());
    //    entity.setYear(registerReq.getYear());
    entity.setDataType(LearnDataType.PRODUCTION.getId());
    entity.setCompareYyyy(registerReq.getCompareYear());
    entity.setTargetYyyy(registerReq.getTargetYyyy());
    entity.setRoundNo(registerReq.getRoundNo() != null ? registerReq.getRoundNo() : 1L);
    entity.setMemo(registerReq.getMemo());
    entity.setStatus(LearnDataRegister.READY.getId());
    entity.setDataType("CREATE");
    entity.setTotalItems(0L);
    entity.setTotalSize(0L);
    entity.setItemCount(0L);
    entity.setDeleted(false);
    entity.setCreatedDttm(ZonedDateTime.now());
    //    entity.setId1(0L); // 임시값

    DatasetEntity savedEntity = datasetClsRepository.save(entity);

    // 저장 후 id1을 dataset_uid와 동일하게 업데이트
    //    savedEntity.setId1(savedEntity.getId());
    //    savedEntity = datasetClsRepository.save(savedEntity);

    return savedEntity.toDto();
  }

  // TODO 미사용 끝
  /**
   * 학습 데이터 수정
   *
   * @param updateReq 수정 요청 데이터
   * @return 수정된 데이터셋 정보
   */
  public void update(UUID uuid, DatasetDto.UpdateReq updateReq) {
    DatasetEntity entity =
        datasetClsRepository
            .findByUuid(uuid)
            .orElseThrow(() -> new NotFoundException("데이터셋을 찾을 수 없습니다. uuid: " + uuid));

    if (StringUtils.isNotBlank(updateReq.getTitle())) {
      entity.setTitle(updateReq.getTitle());
    }
    if (StringUtils.isNotBlank(updateReq.getMemo())) {
      entity.setMemo(updateReq.getMemo());
    }

    datasetClsRepository.save(entity);
  }

  /**
   * 학습데이터 삭제
   *
   * @param uuid 삭제 요청 (데이터셋 ID 목록)
   */
  public void deleteDatasets(UUID uuid) {
    remove(uuid);
  }

  public DatasetDto.Summary getDatasetSummary(DatasetDto.SummaryReq summaryReq) {
    long totalMapSheets = 0;
    long totalFileSize = 0;

    for (Long datasetId : summaryReq.getDatasetIds()) {
      DatasetEntity entity =
          datasetClsRepository
              .findById(datasetId)
              .orElseThrow(() -> new NotFoundException("데이터셋을 찾을 수 없습니다. ID: " + datasetId));

      if (!entity.getDeleted()) {
        totalMapSheets += entity.getTotalItems() != null ? entity.getTotalItems() : 0;
        totalFileSize += entity.getTotalSize() != null ? entity.getTotalSize() : 0;
      }
    }

    double averageMapSheets =
        !summaryReq.getDatasetIds().isEmpty()
            ? (double) totalMapSheets / summaryReq.getDatasetIds().size()
            : 0;

    return new DatasetDto.Summary(
        summaryReq.getDatasetIds().size(), totalMapSheets, totalFileSize, averageMapSheets);
  }

  public Page<DatasetClsObjDto.Basic> searchDatasetClsObjectList(
      DatasetClsObjDto.ClsSearchReq searchReq) {
    Page<DatasetClsObjEntity> entityPage =
        datasetClsRepository.searchDatasetClsObjectList(searchReq);
    return entityPage.map(DatasetClsObjEntity::toDto);
  }

  public UUID deleteDatasetObjByUuid(UUID uuid) {
    DatasetObjEntity entity =
        datasetObjRepository
            .findByUuid(uuid)
            .orElseThrow(() -> new NotFoundException("데이터셋 obj를 찾을 수 없습니다. ID: " + uuid));
    entity.setDeleted(true);
    datasetObjRepository.save(entity);
    return entity.getUuid();
  }

  /**
   * 데이터셋 object class 조회
   *
   * @param uuid dataset uuid
   * @param type compare, target
   * @return
   */
  public List<DatasetClass> findDatasetObjClassByUuid(UUID uuid, String type) {
    return datasetObjRepository.findDatasetObjClassByUuid(uuid, type);
  }

  public Long getDatasetMaxStage(int compareYyyy, int targetYyyy) {
    return datasetClsRepository.getDatasetMaxStage(compareYyyy, targetYyyy);
  }

  @Transactional
  public Long insertDatasetMngData(DatasetMngRegDto mngRegDto) {
    return datasetClsRepository.insertDatasetMngData(mngRegDto);
  }

  public void insertDatasetObj(DatasetObjRegDto objRegDto) {
    datasetObjRepository.insertDatasetObj(objRegDto);
  }

  public String getFilePathByUUIDPathType(UUID uuid, String pathType) {
    return datasetObjRepository.getFilePathByUUIDPathType(uuid, pathType);
  }

  public void insertDatasetTestObj(DatasetObjRegDto objRegDto) {
    datasetObjRepository.insertDatasetTestObj(objRegDto);
  }

  /**
   * 학습데이터셋 마스터 상태 변경
   *
   * @param datasetUid 학습데이터셋 마스터 id
   * @param register 상태
   */
  @Transactional
  public void updateDatasetUploadStatus(Long datasetUid, LearnDataRegister register) {
    DatasetEntity entity =
        datasetClsRepository
            .findById(datasetUid)
            .orElseThrow(() -> new NotFoundException("데이터셋을 찾을 수 없습니다. ID: " + datasetUid));

    entity.setStatus(register.getId());
  }

  public void insertDatasetValObj(DatasetObjRegDto objRegDto) {
    datasetObjRepository.insertDatasetValObj(objRegDto);
  }

  public Long findDatasetByUidExistsCnt(String uid) {
    return datasetClsRepository.findDatasetByUidExistsCnt(uid);
  }

  /**
   * 데이터셋 등록 실패시 Obj 데이터 정리
   *
   * @param datasetUid 모델 마스터 id
   */
  @Transactional
  public void deleteAllDatasetObj(Long datasetUid) {
    int cnt = datasetObjRepository.deleteAllDatasetObj(datasetUid);
    log.info("datasetUid={} 데이터셋 실패 - 전체 삭제 완료. 총 {}건", datasetUid, cnt);
  }

  public void insertDatasetClsObj(DatasetObjDto.DatasetClsObjRegDto objRegDto) {
    datasetClsRepository.insertDatasetClsObj(objRegDto);
  }

  public String getFilePathByUUIDPathTif(UUID uuid) {
    return datasetClsRepository.getFilePathByUUIDPathType(uuid);
  }
}
