package com.hdkj.lt.si.service.remote.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import com.hdkj.hussar.HussarException;
import com.hdkj.hussar.ResultCode;
import com.hdkj.lt.base.exception.ExceptionCast;
import com.hdkj.lt.core.rest.model.AbstractCallResponseEntity;
import com.hdkj.lt.core.rest.service.impl.AbstractDefaultRemoteCallService;
import com.hdkj.lt.modle.dto.psrdevice.PsrDeviceQueryDTO;
import com.hdkj.lt.si.modle.JoinEcTransformerResponseEntity;
import com.hdkj.lt.si.modle.PsrDeviceCommonResponseEntity;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.Charsets;
import org.psr.framework.oauth.config.TokenRestTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

/**
 * @Description
 * @Author wcx
 * @Date 2025/7/29 20:12
 * @Version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PsrDeviceRemoteCallServiceImpl extends AbstractDefaultRemoteCallService {

    private final TokenRestTemplate tokenRestTemplate;

    @Value("${psr.gateway.url}")
    private String requestUri;

    @Override
    public <R> R call(String methodUrl, HttpMethod method, Object requestBody, Class<R> responseBody) {
        CallConfig callConfig = this.buildCallConfig(requestBody);
        String requestUrl = callConfig.getRequestUri().concat(methodUrl);
        Class<? extends AbstractCallResponseEntity> responseType = callConfig.getResponseType();
        String requestBodyStr = JSON.toJSONString(requestBody);
        try {
            HttpEntity<Object> httpEntity = this.createHttpEntity(requestBody);
            ResponseEntity<? extends AbstractCallResponseEntity> restRespEntity = tokenRestTemplate.exchange(requestUrl, method, httpEntity, responseType);
            AbstractCallResponseEntity callRespEntity = restRespEntity.getBody();
            if (!HttpStatus.OK.equals(restRespEntity.getStatusCode()) || Objects.isNull(callRespEntity)) {
                String messagePattern = String.format("call failed, methodUrl: %s,\n requestBody: %s,\n restRespEntity: %s", methodUrl, requestBodyStr, JSON.toJSONString(restRespEntity));
                StringBuilder errorMsg = new StringBuilder(messagePattern);
                Optional.ofNullable(callRespEntity).ifPresent(e -> errorMsg.append(",\n errorMsg：").append(e.getMsg()));
                ExceptionCast.cast(errorMsg.toString());
            }
            SimplePropertyPreFilter excludesFilter = new SimplePropertyPreFilter();
            excludesFilter.getExcludes().addAll(Arrays.asList("code", "data", "msg"));
            log.info("call successful, methodUrl: {},\n requestBody: {},\n callRespEntity: {}", methodUrl, requestBodyStr, JSON.toJSONString(callRespEntity, excludesFilter));
            return JSON.parseObject(JSON.toJSONString(callRespEntity.getData()).replace("#",""), responseBody);
        } catch (Exception e) {
            log.error("call failed, methodUrl: {},\n requestBody: {},\n errorMsg: {}", methodUrl, requestBodyStr, e.toString());
            throw new HussarException(ResultCode.FAILURE.getCode(), e.toString());
        }
    }

    @Override
    protected CallConfig buildCallConfig() {
        return AbstractDefaultRemoteCallService.CallConfig.builder()
                .requestUri(this.requestUri)
                .successCode("000000")
                .build();
    }

    @Override
    protected <T> HttpEntity<T> createHttpEntity(T body) {
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        headers.set(HttpHeaders.ACCEPT_CHARSET, Charsets.UTF_8.toString());
        return new HttpEntity<>(body, headers);
    }

    private <T> CallConfig buildCallConfig(T requestBody) {
        // 构建远程接口基础信息
        CallConfig callConfig = this.buildCallConfig();
        // 补充返回实体对象，便于解析数据
        Class<? extends AbstractCallResponseEntity> clazz;
        if (requestBody instanceof PsrDeviceQueryDTO) {
            clazz = PsrDeviceCommonResponseEntity.class;
        } else {
            clazz = JoinEcTransformerResponseEntity.class;
        }
        callConfig.setResponseType(clazz);
        return callConfig;
    }
}
