package com.imdroid.beidou_ehm.simcard;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imdroid.secapi.dto.*;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.security.MessageDigest;
import java.util.*;

@Service
public class SimCardQueryServiceImpl implements SimCardQueryService{
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Value("${sim.url}")
    private String BASE_URL;
    @Value("${sim.username}")
    private String USERNAME;
    @Value("${sim.key}")
    private String KEY;

    @Autowired
    TrafficCardMapper trafficCardMapper;

    @Autowired
    GnssDeviceMapper gnssDeviceMapper;

    @Override
    public BaseResponse<CardInfoData> queryCardInfo(GnssStatusJoin device) {
        return executeQuery(device, "/api/Service/Cardinfo", CardInfoData.class);
    }

    @Override
    public BaseResponse<CardStatusData> queryCardStatus(GnssStatusJoin device) {
        return executeQuery(device, "/api/Service/QueryCardStatus", CardStatusData.class);
    }

    @Override
    public BaseResponse<GprsData> queryGprs(GnssStatusJoin device) {
        return executeQuery(device, "/api/Service/QueryGprs", GprsData.class);
    }

    @Override
    public BaseResponse<CardDetailData> queryCardDetail(GnssStatusJoin device) {
        return executeQuery(device, "/api/Service/QueryCard", CardDetailData.class);
    }

    private <T> BaseResponse<T> executeQuery(GnssStatusJoin device, String path, Class<T> responseType) {
        try {
            BaseResponse<T> response = queryByParams(device.getIccid(), path, responseType);

            /*
                系统中存在一些奇怪的卡 ：

                向 DTU发送AT指令查询 ICCID 返回的值比如是：89861124224084565106，但实际是 8986112422408456510B，
                从而导致卡商无法查询到该卡，正确的方法是舍弃最后一位，比如 8986112422408456510

                所以，当出现 " 无效的卡号 " 错误的时候，应该尝试去舍弃最后一位， 这样才是正确的 ICCID 号码

            */
            if (shouldTryTruncatedIccid(response) && device.getIccid() != null && device.getIccid().length() > 1) {
                String truncatedIccid = device.getIccid().substring(0, device.getIccid().length() - 1);
                BaseResponse<T> retryResponse = queryByParams(truncatedIccid, path, responseType);
                if (retryResponse != null && retryResponse.getStatus() == 1) {
                    updateGnssDeviceIccid(device, truncatedIccid);
                    device.setIccid(truncatedIccid);
                    return retryResponse;
                }
            }
            
            return response;
        } catch (Exception e) {
            logger.error("查询失败: 设备={}, 错误={}", device.getDeviceid(), e.getMessage());
            return null;
        }
    }

    private <T> BaseResponse<T> queryByParams(String iccid, String path, Class<T> responseType) throws Exception {
        Map<String, String> params = buildQueryParams(iccid);
        String response = sendHttpPost(path, params);
        logger.debug("查询响应: ICCID={}, 响应={}", iccid, response);
        
        return parseResponse(response, responseType);
    }

    private Map<String, String> buildQueryParams(String iccid) {
        Map<String, String> params = new HashMap<>();
        params.put("username", USERNAME);
        params.put("key", KEY);
        params.put("card", iccid);
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        params.put("signature", calculateSignature(params));
        return params;
    }

    private <T> BaseResponse<T> parseResponse(String response, Class<T> responseType) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);

        // 特殊处理CardStatus的数组响应
        if (responseType == CardStatusData.class) {
            JsonNode root = mapper.readTree(response);
            if (root.get("Status").asInt() == 1 && root.get("Data").isArray()) {
                CardStatusData statusData = new CardStatusData();
                statusData.setStatusCode(root.get("Data").get(0).asInt());
                statusData.setStatusDesc(root.get("Data").get(1).asText());
                BaseResponse<CardStatusData> baseResponse = new BaseResponse<>();
                baseResponse.setStatus(1);
                baseResponse.setMessage("Success");
                baseResponse.setData(statusData);
                return (BaseResponse<T>) baseResponse;
            }
        }

        JavaType type = mapper.getTypeFactory().constructParametricType(BaseResponse.class, responseType);
        return mapper.readValue(response, type);
    }

    private boolean shouldTryTruncatedIccid(BaseResponse<?> response) {
        return response != null &&
               (response.getStatus() == 0 || response.getStatus() == -6) && 
               response.getMessage() != null && 
               response.getMessage().contains("无效的卡号");
    }

    private String calculateSignature(Map<String, String> params) {
        try {
            List<String> paramList = new ArrayList<>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                paramList.add(entry.getKey() + "=" + entry.getValue());
            }
            Collections.sort(paramList);

            String paramString = String.join("&", paramList);
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(paramString.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            String signature = sb.toString();
            logger.debug("Signature: {}", signature);
            return signature;

        } catch (Exception e) {
            logger.error("签名计算失败: {}", e.getMessage());
            return null;
        }
    }

    private String sendHttpPost(String path, Map<String, String> params) throws Exception {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(BASE_URL + path);

            List<BasicNameValuePair> pairs = new ArrayList<>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }

            httpPost.setEntity(new UrlEncodedFormEntity(pairs));
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                return EntityUtils.toString(response.getEntity());
            }
        }
    }

    public boolean hasValidIccid(GnssStatusJoin device) {
        return device.getIccid() != null && !device.getIccid().trim().isEmpty();
    }

    public TrafficCard createOrUpdateTrafficCard(GnssStatusJoin device) {
        TrafficCard card = trafficCardMapper.selectById(device.getIccid());
        if (card == null) {
            card = new TrafficCard();
            card.setIccid(device.getIccid());
            card.setStatus(-1);
            card.setUpdatetime(new Date());
            trafficCardMapper.insert(card);
        }
        return card;
    }

    public boolean isValidResponse(BaseResponse<?> response) {
        return response != null && response.getStatus() == 1;
    }

    private void updateGnssDeviceIccid(GnssStatusJoin device, String newIccid) {
        try {
            String originalIccid = device.getIccid();
            
            GnssDevice gnssDevice = gnssDeviceMapper.queryByDeviceId(device.getDeviceid());
            if (gnssDevice != null) {
                gnssDeviceMapper.updateIccidByDeviceId(device.getDeviceid(), newIccid);
                logger.debug("更新设备ICCID: 设备={}, 原ICCID={}, 新ICCID={}",
                        device.getDeviceid(), originalIccid, newIccid);
            }
        } catch (Exception e) {
            logger.error("更新设备ICCID失败: 设备={}, 错误={}", device.getDeviceid(), e.getMessage());
        }
    }
}
