package com.zsElectric.boot.charging.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zsElectric.boot.business.mapper.*;
import com.zsElectric.boot.business.model.entity.ChargeOrderInfo;
import com.zsElectric.boot.business.model.entity.PolicyFee;
import com.zsElectric.boot.business.model.entity.UserAccount;
import com.zsElectric.boot.business.model.entity.UserFirm;
import com.zsElectric.boot.charging.entity.*;
import com.zsElectric.boot.charging.mapper.ThirdPartyChargeStatusMapper;
import com.zsElectric.boot.charging.mapper.ThirdPartyConnectorInfoMapper;
import com.zsElectric.boot.charging.service.ChargingReceptionService;
import com.zsElectric.boot.charging.vo.ChargeResponseVO;
import com.zsElectric.boot.charging.vo.QueryStationStatusVO;
import com.zsElectric.boot.common.constant.ConnectivityConstants;
import com.zsElectric.boot.common.util.electric.ChargingUtil;
import com.zsElectric.boot.common.util.electric.RequestParmsEntity;
import com.zsElectric.boot.common.util.electric.ResponseParmsEntity;
import com.zsElectric.boot.core.exception.BusinessException;
import com.zsElectric.boot.system.mapper.DictItemMapper;
import com.zsElectric.boot.system.model.entity.DictItem;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import static com.zsElectric.boot.common.constant.ConnectivityConstants.FAIL_REASON_NONE;
import static com.zsElectric.boot.common.constant.ConnectivityConstants.STATUS_OK;
import static com.zsElectric.boot.common.util.HmacMD5Util.genSign;
import static com.zsElectric.boot.common.util.HmacMD5Util.verify;

/**
 * 第三方充电推送接收服务实现
 *
 * @author system
 * @since 2025-12-11
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ChargingReceptionServiceImpl implements ChargingReceptionService {

    private final ChargingUtil chargingUtil;
    private final ThirdPartyConnectorInfoMapper connectorInfoMapper;
    private final ThirdPartyChargeStatusMapper chargeStatusMapper;
    private final ObjectMapper objectMapper;
    private final ChargeOrderInfoMapper chargeOrderInfoMapper;
    private final RedissonClient redissonClient;
    private final UserAccountMapper userAccountMapper;
    private final UserFirmMapper userFirmMapper;
    private final PolicyFeeMapper policyFeeMapper;
    private final DictItemMapper dictItemMapper;
    private final ThirdPartyEquipmentInfoMapper thirdPartyEquipmentInfoMapper;

    /** 熔断检查锁前缀 */
    private static final String BREAK_CHECK_LOCK_KEY = "charging:break:check:";
    /** 锁等待时间(秒) */
    private static final long LOCK_WAIT_TIME = 3;
    /** 锁持有时间(秒) */
    private static final long LOCK_LEASE_TIME = 10;

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    // ==================== 接口实现 ====================

    @Override
    public ResponseParmsEntity chargeResponse(RequestParmsEntity requestDTO) {
        log.info("接收推送启动充电结果请求参数：{}", requestDTO);
        return processChargeRequest(requestDTO, jsonNode -> {
            // TODO: 启动充电结果业务处理
            log.debug("启动充电结果 - StartChargeSeq: {}", getTextValue(jsonNode, "StartChargeSeq"));
        });
    }

    @Override
    public ResponseParmsEntity chargeStatusResponse(RequestParmsEntity requestDTO) {
        log.info("接收推送充电状态请求参数：{}", requestDTO);
        return processChargeRequest(requestDTO, this::saveOrUpdateChargeStatus);
    }

    @Override
    public ResponseParmsEntity stopChargeResponse(RequestParmsEntity requestDTO) {
        log.info("接收推送停止充电结果请求参数：{}", requestDTO);
        return processChargeRequest(requestDTO, jsonNode -> {
            // TODO: 停止充电结果业务处理
            log.debug("停止充电结果 - StartChargeSeq: {}", getTextValue(jsonNode, "StartChargeSeq"));
        });
    }

    @Override
    public ResponseParmsEntity chargeOrderResponse(RequestParmsEntity requestDTO) {
        log.info("接收推送充电订单信息请求参数：{}", requestDTO);
        return processChargeRequest(requestDTO, jsonNode -> {
            // TODO: 充电订单信息业务处理
            log.debug("充电订单信息 - StartChargeSeq: {}", getTextValue(jsonNode, "StartChargeSeq"));
        });
    }

    @Override
    public ResponseParmsEntity stationStatus(RequestParmsEntity requestDTO) {
        log.info("接收设备状态变化推送请求参数：{}", requestDTO);
        return processStationStatusRequest(requestDTO);
    }

    // ==================== 公共处理方法 ====================

    /**
     * 通用充电请求处理模板
     */
    private ResponseParmsEntity processChargeRequest(RequestParmsEntity requestDTO, Consumer<JsonNode> businessHandler) {
        try {
            JsonNode jsonNode = verifyAndDecrypt(requestDTO);
            
            // 执行业务处理
            businessHandler.accept(jsonNode);
            
            // 构建响应
            return buildChargeResponse(getTextValue(jsonNode, "StartChargeSeq"));
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("处理请求失败：{}", e.getMessage());
            throw new BusinessException("处理请求失败：" + e.getMessage(), e);
        }
    }

    /**
     * 处理设备状态变化推送请求
     */
    private ResponseParmsEntity processStationStatusRequest(RequestParmsEntity requestDTO) {
        try {
            String decryptData = verifyAndDecryptRaw(requestDTO);
            
            // 解析并更新设备状态
            QueryStationStatusVO stationStatusVO = objectMapper.readValue(decryptData, QueryStationStatusVO.class);
            updateConnectorStatus(stationStatusVO);
            
            // 构建响应
            return buildStatusResponse();
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("处理设备状态推送失败：{}", e.getMessage());
            throw new BusinessException("处理设备状态推送失败：" + e.getMessage(), e);
        }
    }

    /**
     * 验签并解密请求数据
     */
    private JsonNode verifyAndDecrypt(RequestParmsEntity requestDTO) throws Exception {
        String decryptData = verifyAndDecryptRaw(requestDTO);
        return objectMapper.readTree(decryptData);
    }

    /**
     * 验签并解密请求数据（返回原始字符串）
     */
    private String verifyAndDecryptRaw(RequestParmsEntity requestDTO) throws Exception {
        String signData = requestDTO.getOperatorID() + requestDTO.getData() + requestDTO.getTimeStamp() + requestDTO.getSeq();
        if (!verify(signData, ConnectivityConstants.SIG_SECRET, requestDTO.getSig())) {
            log.error("数据验签失败");
            throw new BusinessException("数据验签失败");
        }
        String decryptData = chargingUtil.decryptData(requestDTO.getData());
        log.info("==================== 解密数据开始 ====================");
        log.info("操作员ID: {}", requestDTO.getOperatorID());
        log.info("解密后的数据：{}", decryptData);
        log.info("==================== 解密数据结束 ====================");
        return decryptData;
    }

    // ==================== 响应构建 ====================

    /**
     * 构建充电响应
     */
    private ResponseParmsEntity buildChargeResponse(String startChargeSeq) throws Exception {
        ChargeResponseVO chargeResponseVO = new ChargeResponseVO();
        chargeResponseVO.setStartChargeSeq(startChargeSeq);
        chargeResponseVO.setSuccStat(STATUS_OK);
        chargeResponseVO.setFailReason(FAIL_REASON_NONE);
        
        String encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(chargeResponseVO));
        String sign = genSign(STATUS_OK, "请求成功", encryptData, ConnectivityConstants.SIG_SECRET);
        
        ResponseParmsEntity response = new ResponseParmsEntity();
        response.setRet(STATUS_OK);
        response.setMsg("请求成功");
        response.setData(encryptData);
        response.setSig(sign);
        return response;
    }

    /**
     * 构建设备状态响应
     */
    private ResponseParmsEntity buildStatusResponse() throws Exception {
        Map<String, Integer> statusMap = new HashMap<>();
        statusMap.put("Status", 0);
        
        String encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(statusMap));
        String sign = genSign(STATUS_OK, "", encryptData, ConnectivityConstants.SIG_SECRET);
        
        ResponseParmsEntity response = new ResponseParmsEntity();
        response.setRet(STATUS_OK);
        response.setMsg("");
        response.setData(encryptData);
        response.setSig(sign);
        return response;
    }

    // ==================== 状态更新 ====================

    /**
     * 更新充电接口状态
     */
    private void updateConnectorStatus(QueryStationStatusVO stationStatusVO) {
        if (stationStatusVO == null || CollectionUtils.isEmpty(stationStatusVO.getStationStatusInfos())) {
            return;
        }
        for (StationStatusInfo stationStatusInfo : stationStatusVO.getStationStatusInfos()) {
            List<ConnectorStatusInfo> connectorStatusInfos = stationStatusInfo.getConnectorStatusInfos();
            if (CollectionUtils.isEmpty(connectorStatusInfos)) {
                continue;
            }
            for (ConnectorStatusInfo connectorStatus : connectorStatusInfos) {
                connectorInfoMapper.update(null, Wrappers.<ThirdPartyConnectorInfo>lambdaUpdate()
                        .eq(ThirdPartyConnectorInfo::getConnectorId, connectorStatus.getConnectorID())
                        .set(ThirdPartyConnectorInfo::getStatus, connectorStatus.getStatus()));
                log.debug("更新充电接口状态 - connectorId: {}, status: {}",
                        connectorStatus.getConnectorID(), connectorStatus.getStatus());
            }
        }
    }

    /**
     * 保存或更新充电状态数据
     */
    private void saveOrUpdateChargeStatus(JsonNode jsonNode) {
        try {
            String startChargeSeq = jsonNode.get("StartChargeSeq").asText();

            // 查询是否已存在该订单
            ThirdPartyChargeStatus existing = chargeStatusMapper.selectOne(
                    Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
                            .eq(ThirdPartyChargeStatus::getStartChargeSeq, startChargeSeq)
            );

            ThirdPartyChargeStatus chargeStatus = (existing != null) ? existing : new ThirdPartyChargeStatus();

            // 设置字段值
            chargeStatus.setStartChargeSeq(startChargeSeq);
            chargeStatus.setConnectorId(getTextValue(jsonNode, "ConnectorID"));
            chargeStatus.setConnectorStatus(getIntValue(jsonNode, "ConnectorStatus"));
            chargeStatus.setStartChargeSeqStat(getIntValue(jsonNode, "StartChargeSeqStat"));
            chargeStatus.setStartTime(parseDateTime(getTextValue(jsonNode, "StartTime")));
            chargeStatus.setEndTime(parseDateTime(getTextValue(jsonNode, "EndTime")));
            chargeStatus.setTotalPower(getDecimalValue(jsonNode, "TotalPower"));
            chargeStatus.setTotalMoney(getDecimalValue(jsonNode, "TotalMoney"));
            chargeStatus.setElecMoney(getDecimalValue(jsonNode, "ElecMoney"));
            chargeStatus.setServiceMoney(getDecimalValue(jsonNode, "SeviceMoney")); // 注意：第三方字段名SeviceMoney
            chargeStatus.setSoc(getIntValue(jsonNode, "Soc"));
            chargeStatus.setVoltageA(getDecimalValue(jsonNode, "VoltageA"));
            chargeStatus.setVoltageB(getDecimalValue(jsonNode, "VoltageB"));
            chargeStatus.setVoltageC(getDecimalValue(jsonNode, "VoltageC"));
            chargeStatus.setCurrentA(getDecimalValue(jsonNode, "CurrentA"));
            chargeStatus.setCurrentB(getDecimalValue(jsonNode, "CurrentB"));
            chargeStatus.setCurrentC(getDecimalValue(jsonNode, "CurrentC"));

            if (existing != null) {
                chargeStatus.setUpdateTime(LocalDateTime.now());
                chargeStatusMapper.updateById(chargeStatus);
                log.info("更新充电状态成功 - startChargeSeq: {}", startChargeSeq);
            } else {
                chargeStatus.setCreateTime(LocalDateTime.now());
                chargeStatusMapper.insert(chargeStatus);
                log.info("新增充电状态成功 - startChargeSeq: {}", startChargeSeq);
            }
            //熔断保护
            isNeedBreak(chargeStatus);
        } catch (Exception e) {
            log.error("保存充电状态数据失败", e);
        }
    }

    // ==================== JSON解析工具方法 ====================

    private String getTextValue(JsonNode node, String fieldName) {
        JsonNode field = node.get(fieldName);
        return (field != null && !field.isNull()) ? field.asText() : null;
    }

    private Integer getIntValue(JsonNode node, String fieldName) {
        JsonNode field = node.get(fieldName);
        return (field != null && !field.isNull()) ? field.asInt() : null;
    }

    private BigDecimal getDecimalValue(JsonNode node, String fieldName) {
        JsonNode field = node.get(fieldName);
        return (field != null && !field.isNull()) ? new BigDecimal(field.asText()) : null;
    }

    private LocalDateTime parseDateTime(String dateTimeStr) {
        if (dateTimeStr == null || dateTimeStr.isEmpty()) {
            return null;
        }
        try {
            return LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMATTER);
        } catch (Exception e) {
            log.warn("解析时间失败: {}", dateTimeStr);
            return null;
        }
    }

    /**
     * 根据充电订单号StartChargeSeq 获取订单信息判断是否需要熔断，提前跳枪
     * 使用分布式锁防止并发重复检查
     */
    private void isNeedBreak(ThirdPartyChargeStatus chargeStatus) {
        String lockKey = BREAK_CHECK_LOCK_KEY + chargeStatus.getStartChargeSeq();
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁，最多等待3秒，持有锁最多10秒
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS)) {
                try {
                    ChargeOrderInfo chargeOrderInfo = chargeOrderInfoMapper.selectOne(
                            Wrappers.<ChargeOrderInfo>lambdaQuery()
                                    .eq(ChargeOrderInfo::getChargeOrderNo, chargeStatus.getStartChargeSeq())
                                    .eq(ChargeOrderInfo::getStatus, 1)
                                    .eq(ChargeOrderInfo::getIsDeleted, 0)
                    );
                    if (null != chargeOrderInfo) {
                        // TODO: 根据业务需求实现熔断条件判断（例如：余额不足、超时等）
                        DictItem dictItem = dictItemMapper.selectOne(
                                new LambdaQueryWrapper<DictItem>()
                                        .eq(DictItem::getDictCode, "up_recharge")
                                        .eq(DictItem::getStatus, 1)
                                        .last("LIMIT 1"));
                        //安全价
                        BigDecimal upRecharge = new BigDecimal(dictItem.getValue());
                        //获取用户余额
                        BigDecimal balance = userAccountMapper.selectOne(Wrappers.<UserAccount>lambdaQuery()
                                .eq(UserAccount::getUserId, chargeOrderInfo.getUserId())
                                .eq(UserAccount::getIsDeleted, 0)).getBalance();
                        //企业价
                        BigDecimal firmPrice;
                        //根据用户ID去查询当前用户是否有归属企业
                        UserFirm userFirm = userFirmMapper.selectOne(Wrappers.<UserFirm>lambdaQuery()
                                .eq(UserFirm::getUserId, chargeOrderInfo.getUserId())
                                .eq(UserFirm::getIsDeleted, 0));
                        if(null != userFirm){
                            ThirdPartyEquipmentInfo thirdPartyEquipmentInfo = thirdPartyEquipmentInfoMapper.selectOne(Wrappers.<ThirdPartyEquipmentInfo>lambdaQuery()
                                    .eq(ThirdPartyEquipmentInfo::getEquipmentId, chargeOrderInfo.getEquipmentId())
                                    .eq(ThirdPartyEquipmentInfo::getIsDeleted, 0));
                            List<PolicyFee> policyFees = policyFeeMapper.selectList(Wrappers.<PolicyFee>lambdaQuery()
                                    .eq(PolicyFee::getStationInfoId, thirdPartyEquipmentInfo.getStationId())
                                    .eq(PolicyFee::getFirmId, userFirm.getFirmId()));
                        }

                    }
                } finally {
                    lock.unlock();
                }
            } else {
                log.warn("获取熔断检查锁超时 - startChargeSeq: {}", chargeStatus.getStartChargeSeq());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("获取熔断检查锁被中断 - startChargeSeq: {}", chargeStatus.getStartChargeSeq(), e);
        }
    }
}
