package go.kr.project.api.service.impl;

import egovframework.exception.MessageException;
import go.kr.project.api.config.ApiConstant;
import go.kr.project.api.config.properties.VmisProperties;
import go.kr.project.api.service.ExternalVehicleApiService;
import go.kr.project.api.util.ExceptionDetailUtil;
import go.kr.project.api.model.Envelope;
import go.kr.project.api.model.VehicleApiResponseVO;
import go.kr.project.api.model.request.BasicRequest;
import go.kr.project.api.model.request.LedgerRequest;
import go.kr.project.api.model.response.*;
import go.kr.project.api.service.VmisCarBassMatterInqireLogService;
import go.kr.project.api.service.VmisCarLedgerFrmbkLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * 외부 VMIS-interface API 호출 서비스 구현체
 * VMIS-interface 프로그램의 API를 호출하여 차량 정보를 조회하는 서비스
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ExternalVehicleApiServiceImpl extends EgovAbstractServiceImpl implements ExternalVehicleApiService {

    private final RestTemplate restTemplate;
    private final VmisProperties vmisProperties; // 프로퍼티 주입 (외부 API URL 구성에 사용)
    private final VmisCarBassMatterInqireLogService bassMatterLogService; // 기본사항 조회 로그 서비스
    private final VmisCarLedgerFrmbkLogService ledgerLogService; // 등록원부 로그 서비스

    /**
     * 차량 기본정보 조회 API 호출
     * 중요 로직: 기본정보 조회는 BasicRequest 전체를 받아서 외부 API에 전달
     * (차량번호, 부과기준일, 조회구분, 차대번호 등 필수 파라미터 포함)
     *
     * @param request 기본정보 조회 요청 (차량번호, 부과기준일, 조회구분 등 포함)
     * @return 차량 기본정보
     */
    @Override
    public BasicResponse getBasicInfo(BasicRequest request) {
        log.debug("차량 기본정보 조회 API 호출 - 차량번호: {}", request.getVhrno());

        String generatedId = null;
        try {
            // 1) 최초 요청 로그 저장 (별도 트랜잭션)
            VmisCarBassMatterInqireVO logEntity = VmisCarBassMatterInqireVO.fromRequest(request);
            generatedId = bassMatterLogService.createInitialRequestNewTx(logEntity);

            // Envelope로 감싸기 (요청 객체는 이미 모든 필수 파라미터를 포함)
            Envelope<BasicRequest> requestEnvelope = new Envelope<>(request);

            // HTTP 헤더 설정
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<Envelope<BasicRequest>> requestEntity = new HttpEntity<>(requestEnvelope, headers);

            // 2) API 호출
            ResponseEntity<Envelope<BasicResponse>> responseEntity = restTemplate.exchange(
                    vmisProperties.getExternal().getApi().getUrl().buildBasicUrl(),
                    HttpMethod.POST,
                    requestEntity,
                    new ParameterizedTypeReference<Envelope<BasicResponse>>() {}
            );

            // 3) 응답 로그 업데이트 (별도 트랜잭션)
            if (responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() != null) {
                List<BasicResponse> data = responseEntity.getBody().getData();
                if (data != null && !data.isEmpty()) {
                    VmisCarBassMatterInqireVO update = VmisCarBassMatterInqireVO.fromResponse(generatedId, responseEntity.getBody());
                    if (update != null) {
                        bassMatterLogService.updateResponseNewTx(update);
                    }
                    return data.get(0);
                }
            }

            log.warn("차량 기본정보 조회 응답이 비어있음 - 차량번호: {}", request.getVhrno());
            return null;

        } catch (Exception e) {
            // 4) 오류 로그 업데이트 (별도 트랜잭션)
            if (generatedId != null) {
                try {
                    String detail = ExceptionDetailUtil.buildForLog(e);
                    VmisCarBassMatterInqireVO errorLog = VmisCarBassMatterInqireVO.builder()
                            .carBassMatterInqireId(generatedId)
                            .cntcResultCode(ApiConstant.CNTC_RESULT_CODE_ERROR)
                            .cntcResultDtls(detail)
                            .build();
                    bassMatterLogService.updateResponseNewTx(errorLog);
                    log.error("[EXTERNAL-BASIC-ERR-LOG] API 호출 에러 정보 저장 완료(별도TX) - ID: {}, detail: {}", generatedId, detail, e);
                } catch (Exception ignore) {
                    log.error("[EXTERNAL-BASIC-ERR-LOG] 에러 로그 저장 실패 - ID: {}", generatedId, ignore);
                }
            }
            log.error("차량 기본정보 조회 API 호출 실패 - 차량번호: {}", request.getVhrno(), e);
            throw new MessageException("차량 기본정보 조회 실패: " + e.getMessage(), e);
        }
    }

    /**
     * 자동차 등록원부(갑) 조회 API 호출
     * 중요 로직: 등록원부 조회는 차량번호 외에 소유자정보, 조회구분 등 필수 파라미터를 받아서 호출
     * 
     * @param request 등록원부 조회 요청 (차량번호, 소유자정보, 조회구분 등 포함)
     * @return 등록원부 정보
     */
    @Override
    public LedgerResponse getLedgerInfo(LedgerRequest request) {
        log.debug("자동차 등록원부 조회 API 호출 - 차량번호: {}", request.getVhrno());

        String generatedId = null;
        try {
            // 1) 최초 요청 로그 저장 (별도 트랜잭션)
            VmisCarLedgerFrmbkVO init = VmisCarLedgerFrmbkVO.fromRequest(request);
            generatedId = ledgerLogService.createInitialRequestNewTx(init);

            // Envelope로 감싸기 (요청 객체는 이미 모든 필수 파라미터를 포함)
            Envelope<LedgerRequest> requestEnvelope = new Envelope<>(request);

            // HTTP 헤더 설정
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<Envelope<LedgerRequest>> requestEntity = new HttpEntity<>(requestEnvelope, headers);

            // 2) API 호출
            ResponseEntity<Envelope<LedgerResponse>> responseEntity = restTemplate.exchange(
                    vmisProperties.getExternal().getApi().getUrl().buildLedgerUrl(),
                    HttpMethod.POST,
                    requestEntity,
                    new ParameterizedTypeReference<Envelope<LedgerResponse>>() {}
            );

            // 3) 응답 로그 업데이트 (마스터 + 상세, 별도 트랜잭션)
            if (responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() != null) {
                List<LedgerResponse> data = responseEntity.getBody().getData();
                if (data != null && !data.isEmpty()) {
                    LedgerResponse body = data.get(0);
                    VmisCarLedgerFrmbkVO masterUpdate = VmisCarLedgerFrmbkVO.fromResponseMaster(generatedId, body);
                    ledgerLogService.updateResponseNewTx(masterUpdate);

                    List<VmisCarLedgerFrmbkDtlVO> details = VmisCarLedgerFrmbkDtlVO.listFromResponse(body, generatedId);
                    if (details != null && !details.isEmpty()) {
                        ledgerLogService.saveDetailsNewTx(generatedId, details);
                    }
                    return body;
                }
            }

            log.warn("자동차 등록원부 조회 응답이 비어있음 - 차량번호: {}", request.getVhrno());
            return null;

        } catch (Exception e) {
            // 4) 오류 로그 업데이트 (별도 트랜잭션)
            if (generatedId != null) {
                try {
                    String detail = ExceptionDetailUtil.buildForLog(e);
                    VmisCarLedgerFrmbkVO errorLog = VmisCarLedgerFrmbkVO.builder()
                            .carLedgerFrmbkId(generatedId)
                            .cntcResultCode(ApiConstant.CNTC_RESULT_CODE_ERROR)
                            .cntcResultDtls(detail)
                            .build();
                    ledgerLogService.updateResponseNewTx(errorLog);
                    log.error("[EXTERNAL-LEDGER-ERR-LOG] API 호출 에러 정보 저장 완료(별도TX) - ID: {}, detail: {}", generatedId, detail, e);
                } catch (Exception ignore) {
                    log.error("[EXTERNAL-LEDGER-ERR-LOG] 에러 로그 저장 실패 - ID: {}", generatedId, ignore);
                }
            }
            log.error("자동차 등록원부 조회 API 호출 실패 - 차량번호: {}", request.getVhrno(), e);
            throw new MessageException("자동차 등록원부 조회 실패: " + e.getMessage(), e);
        }
    }
}
