package com.kamco.cd.training.common.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.training.code.dto.CommonCodeDto.Basic;
import com.kamco.cd.training.code.service.CommonCodeService;
import com.kamco.cd.training.config.api.ApiResponseDto;
import java.util.List;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 공통코드 조회 유틸리티 클래스 애플리케이션 전역에서 공통코드를 조회하기 위한 유틸리티입니다. training 서버는 Redis 사용하고 Spring 내장 메모리 캐시
 * 사용합니다.
 */
//
@Slf4j
@Component
public class CommonCodeUtil {

  private final CommonCodeService commonCodeService;

  @Autowired private ObjectMapper objectMapper;

  public CommonCodeUtil(CommonCodeService commonCodeService) {
    this.commonCodeService = commonCodeService;
  }

  /**
   * 모든 공통코드 조회
   *
   * @return 캐시된 모든 공통코드 목록
   */
  public List<Basic> getAllCommonCodes() {
    try {
      return commonCodeService.getFindAll();
    } catch (Exception e) {
      log.error("공통코드 전체 조회 중 오류 발생", e);
      return List.of();
    }
  }

  /**
   * 특정 코드로 공통코드 조회
   *
   * @param code 코드값
   * @return 해당 코드의 공통코드 목록
   */
  public List<Basic> getCommonCodesByCode(String code) {
    if (code == null || code.isEmpty()) {
      log.warn("유효하지 않은 코드: {}", code);
      return List.of();
    }

    try {
      return commonCodeService.findByCode(code);
    } catch (Exception e) {
      log.error("코드 기반 공통코드 조회 중 오류 발생: {}", code, e);
      return List.of();
    }
  }

  /**
   * 특정 ID로 공통코드 단건 조회
   *
   * @param id 공통코드 ID
   * @return 조회된 공통코드
   */
  public Optional<Basic> getCommonCodeById(Long id) {
    if (id == null || id <= 0) {
      log.warn("유효하지 않은 ID: {}", id);
      return Optional.empty();
    }

    try {
      return Optional.of(commonCodeService.getOneById(id));
    } catch (Exception e) {
      log.error("ID 기반 공통코드 조회 중 오류 발생: {}", id, e);
      return Optional.empty();
    }
  }

  /**
   * 상위 코드와 하위 코드로 공통코드명 조회
   *
   * @param parentCode 상위 코드
   * @param childCode 하위 코드
   * @return 공통코드명
   */
  public Optional<String> getCodeName(String parentCode, String childCode) {
    if (parentCode == null || parentCode.isEmpty() || childCode == null || childCode.isEmpty()) {
      log.warn("유효하지 않은 코드: parentCode={}, childCode={}", parentCode, childCode);
      return Optional.empty();
    }

    try {
      return commonCodeService.getCode(parentCode, childCode);
    } catch (Exception e) {
      log.error("코드명 조회 중 오류 발생: parentCode={}, childCode={}", parentCode, childCode, e);
      return Optional.empty();
    }
  }

  /**
   * 상위 코드를 기반으로 하위 코드 조회
   *
   * @param parentCode 상위 코드
   * @return 해당 상위 코드의 하위 공통코드 목록
   */
  public List<Basic> getChildCodesByParentCode(String parentCode) {
    if (parentCode == null || parentCode.isEmpty()) {
      log.warn("유효하지 않은 상위 코드: {}", parentCode);
      return List.of();
    }

    try {
      return commonCodeService.getFindAll().stream()
          .filter(code -> parentCode.equals(code.getCode()))
          .findFirst()
          .map(Basic::getChildren)
          .orElse(List.of());
    } catch (Exception e) {
      log.error("상위 코드 기반 하위 코드 조회 중 오류 발생: {}", parentCode, e);
      return List.of();
    }
  }

  /**
   * 코드 사용 가능 여부 확인
   *
   * @param parentId 상위 코드 ID -> 1depth 는 null 허용 (파라미터 미필수로 변경)
   * @param code 확인할 코드값
   * @return 사용 가능 여부 (true: 사용 가능, false: 중복 또는 오류)
   */
  public boolean isCodeAvailable(Long parentId, String code) {
    if (parentId <= 0 || code == null || code.isEmpty()) {
      log.warn("유효하지 않은 입력: parentId={}, code={}", parentId, code);
      return false;
    }

    try {
      ApiResponseDto.ResponseObj response = commonCodeService.getCodeCheckDuplicate(parentId, code);
      // ResponseObj의 code 필드 : OK이면 성공, 아니면 실패
      return response.getCode() != null
          && response.getCode().equals(ApiResponseDto.ApiResponseCode.OK);
    } catch (Exception e) {
      log.error("코드 중복 확인 중 오류 발생: parentId={}, code={}", parentId, code, e);
      return false;
    }
  }
}
