package org.dromara.main.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.main.config.WxPayConfig;
import org.dromara.main.domain.*;
import org.dromara.main.domain.bo.CsOrderCardBo;
import org.dromara.main.domain.vo.CsMessageVo;
import org.dromara.main.domain.vo.CsOrderCardVo;
import org.dromara.main.mapper.CsMessageMapper;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.dromara.main.mapper.CsOrderCardMapper;
import org.dromara.main.mapper.CsSessionMapper;
import org.dromara.main.mapper.MainExamEvaluationMapper;
import org.dromara.main.mapper.MainOrderMapper;
import org.dromara.main.mapper.MainPositionMapper;
import org.dromara.main.mapper.MainStudentMapper;
import org.dromara.main.service.ICsOrderCardService;
import org.dromara.main.service.ICsSessionService;
import org.dromara.main.service.IMainMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@RequiredArgsConstructor
@Service
public class CsOrderCardServiceImpl implements ICsOrderCardService {

    private final CsOrderCardMapper baseMapper;
    private final CsMessageMapper messageMapper;
    private final ICsSessionService sessionService;
    private final IMainMessageService mainMessageService;
    private final Converter converter;
    private final SimpMessagingTemplate messagingTemplate;
    private final MainOrderMapper orderMapper;
    private final MainStudentMapper studentMapper;
    private final CsSessionMapper sessionMapper;
    private final MainExamEvaluationMapper examEvaluationMapper;
    private final MainPositionMapper mainPositionMapper;
    @Autowired
    private WxPayConfig wxPayConfig;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CsOrderCardVo sendOrderCard(CsOrderCardBo bo) {
        // 解析发送者ID（优先使用传入值，fallback 到当前登录用户）
        Long senderId = bo.getSenderId() != null ? bo.getSenderId() : LoginHelper.getUserId();
        
        // 动态解析发送者类型
        CsSession session = sessionMapper.selectById(bo.getSessionId());
        Integer senderType = 2; // 默认为客服（手动发送结算单只从总控端调用）
        if (senderId != null && session != null && session.getFromUserId() != null && session.getFromUserId().equals(senderId)) {
            senderType = 1; // 极端情况：用户自己发的
        }
        
        CsMessage message = new CsMessage();
        message.setSessionId(bo.getSessionId());
        message.setMsgNo(bo.getMsgNo());
        message.setSenderType(senderType);
        message.setSenderId(senderId);
        message.setMsgType("order_card");
        message.setStatus(1);
        message.setIsRead(0);
        message.setSendTime(LocalDateTime.now());
        messageMapper.insert(message);

        CsOrderCard orderCard = new CsOrderCard();
        orderCard.setMsgId(message.getId());
        orderCard.setSessionId(bo.getSessionId());
        orderCard.setOrderName(bo.getOrderName());
        orderCard.setOrderPrice(bo.getOrderPrice());
        orderCard.setOrderType(bo.getOrderType());
        orderCard.setTenantId(bo.getTenantId());
        orderCard.setStatus("pending");
        orderCard.setExpireTime(LocalDateTime.now().plusSeconds(60));
        orderCard.setCreateTime(LocalDateTime.now());
        baseMapper.insert(orderCard);

        Map<String, Object> payload = new HashMap<>();
        payload.put("orderCardId", orderCard.getId());
        payload.put("name", orderCard.getOrderName());
        payload.put("price", orderCard.getOrderPrice().toString());
        payload.put("status", "pending");
        payload.put("expireTime", orderCard.getExpireTime().toString());
        payload.put("countdownSeconds", 60);
        message.setPayload(JSONUtil.toJsonStr(payload));
        messageMapper.updateById(message);

        sessionService.updateLastMessage(bo.getSessionId(), "[结算单]" + bo.getOrderName());

        // 推送消息到会话频道（与 CsMessageServiceImpl 保持一致）
        CsMessageVo msgVo = new CsMessageVo();
        msgVo.setId(message.getId());
        msgVo.setSessionId(message.getSessionId());
        msgVo.setMsgNo(message.getMsgNo());
        msgVo.setSenderType(message.getSenderType());
        msgVo.setSenderId(message.getSenderId());
        msgVo.setMsgType(message.getMsgType());
        msgVo.setPayload(message.getPayload());
        msgVo.setStatus(message.getStatus());
        msgVo.setSendTime(message.getSendTime());
        // 设置 senderRole，确保前端正确识别发送者
        if (message.getSenderType() == 2) {
            msgVo.setSenderRole("waiter");
        } else if (message.getSenderType() == 3) {
            msgVo.setSenderRole("system");
        } else {
            msgVo.setSenderRole("user");
        }
        messagingTemplate.convertAndSend("/topic/session/" + bo.getSessionId(), msgVo);
        // 通知坐席
        if (session != null && session.getWaiterId() != null) {
            messagingTemplate.convertAndSendToUser(
                session.getWaiterId().toString(),
                "/queue/notify",
                msgVo
            );
        }

        CsOrderCardVo vo = converter.convert(orderCard, CsOrderCardVo.class);
        if (vo != null) {
            vo.setOrderCardId(orderCard.getId());
            vo.setSenderType(senderType);
            vo.setCountdownSeconds(60L);
        }
        return vo;
    }

    @Override
    public CsOrderCardVo queryById(Long orderCardId) {
        CsOrderCard entity = baseMapper.selectById(orderCardId);
        CsOrderCardVo vo = converter.convert(entity, CsOrderCardVo.class);
        if (vo != null) {
            vo.setOrderCardId(entity.getId());
            if ("pending".equals(vo.getStatus())) {
                long seconds = Duration.between(LocalDateTime.now(), vo.getExpireTime()).getSeconds();
                vo.setCountdownSeconds(Math.max(0, seconds));
            }
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean payOrderCard(Long orderCardId, Long userId) {
        CsOrderCard orderCard = baseMapper.selectById(orderCardId);
        if (orderCard == null) {
            throw new RuntimeException("结算单不存在");
        }
        if (!"pending".equals(orderCard.getStatus())) {
            throw new RuntimeException("结算单状态异常");
        }
        if (LocalDateTime.now().isAfter(orderCard.getExpireTime())) {
            orderCard.setStatus("expired");
            baseMapper.updateById(orderCard);
            throw new RuntimeException("结算单已过期");
        }

        orderCard.setStatus("paid");
        orderCard.setPayTime(LocalDateTime.now());
        return baseMapper.updateById(orderCard) > 0;
    }

    @Override
    public Boolean cancelOrderCard(Long orderCardId) {
        CsOrderCard update = new CsOrderCard();
        update.setId(orderCardId);
        update.setStatus("cancelled");
        return baseMapper.updateById(update) > 0;
    }

    @Override
    public void checkExpiredOrderCards() {
        List<CsOrderCard> expiredCards = baseMapper.selectList(Wrappers.<CsOrderCard>lambdaQuery()
                .eq(CsOrderCard::getStatus, "pending")
                .le(CsOrderCard::getExpireTime, LocalDateTime.now()));
        if (!expiredCards.isEmpty()) {
            for (CsOrderCard card : expiredCards) {
                card.setStatus("expired");
                baseMapper.updateById(card);
                // 这里可以根据情况扩展同步改变消息 payload 状状态
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object>createPayOrder(Long orderCardId,Long userId) {
        log.info("========== createPayOrder 入参: orderCardId={}, userId={} ==========", orderCardId, userId);
        CsOrderCard orderCard = baseMapper.selectById(orderCardId);
        if (orderCard == null) {
            log.error("结算单不存在, orderCardId={}", orderCardId);
            throw new RuntimeException("结算单不存在");
        }
        log.info("结算单查询成功: id={}, status={}, sessionId={}, orderPrice={}", orderCard.getId(), orderCard.getStatus(), orderCard.getSessionId(), orderCard.getOrderPrice());
        if (!"pending".equals(orderCard.getStatus())) {
            throw new RuntimeException("结算单状态异常");
        }

        MainStudent student = studentMapper.selectById(userId);
        log.info("学员查询结果: userId={}, student={}", userId, student != null ? "id=" + student.getId() + ",name=" + student.getName() + ",openid=" + student.getOpenid() : "NULL");
        if (student == null) {
            // 尝试通过 tenantId + mobile 查找，或者给出更详细的错误信息
            log.error("用户不存在, 传入userId={}, 尝试检查main_student表是否有此ID", userId);
            throw new ServiceException("用户不存在[userId=" + userId + "]");
        }
        if(StringUtils.isEmpty(student.getOpenid())){
            throw new ServiceException("用户未绑定微信");
        }
        MainOrder mainOrder= new MainOrder();

        mainOrder.setOrderNo(generateOrderNo());
        mainOrder.setOrderType(2);
        mainOrder.setBuyerType(2);
        mainOrder.setBuyerId(userId);
        mainOrder.setBuyerName(student.getName());
        mainOrder.setSource("miniapp");
        mainOrder.setSellerId(1L);
        mainOrder.setTotalAmount(defaultAmount(orderCard.getOrderPrice()));
        mainOrder.setPaidAmount(BigDecimal.ZERO);
        mainOrder.setRefundAmount(BigDecimal.ZERO);
        mainOrder.setOrderStatus(0);
        mainOrder.setPayStatus(0);
        mainOrder.setBusinessId(orderCard.getId());
        mainOrder.setProductId(orderCard.getId());
        // 优先使用结算单上的tenantId，其次用学员的
        String tenantId = StringUtils.isNotBlank(orderCard.getTenantId()) ? orderCard.getTenantId() : student.getTenantId();
        mainOrder.setTenantId(tenantId);
        mainOrder.setRemark(orderCard.getOrderName());
        log.info("创建订单 - 结算单ID: {}, 结算单价格: {}, 转换后的订单价格: {}", orderCard.getId(), orderCard.getOrderPrice(), mainOrder.getTotalAmount());
        orderMapper.insert(mainOrder);

        // 回写主订单ID到结算单
        orderCard.setOriginalOrderId(mainOrder.getId());
        baseMapper.updateById(orderCard);

        try {
            log.info("生成微信支付参数 - OpenID: {}, 传入价格: {}, 订单号: {}, notifyUrl: {}",
                student.getOpenid(), orderCard.getOrderPrice(), mainOrder.getOrderNo(), wxPayConfig.getNotifyUrl());
            Map<String, String> wxPayParams = wxPayConfig.createJsapiPayParams(
                student.getOpenid(),
                orderCard.getOrderPrice(),
                orderCard.getOrderName(),
                mainOrder.getOrderNo()
            );

            // 更新订单的预支付ID
            mainOrder.setWechatOrderId(wxPayParams.get("prepayId"));
            orderMapper.updateById(mainOrder);

            // 原有的返回格式保持不变
            Map<String, Object> result = new LinkedHashMap<>();
            result.put("success", true);
            result.put("orderCardId", orderCard.getId());
            result.put("orderId", mainOrder.getId());
            result.put("orderNo", mainOrder.getOrderNo());
            result.put("amount", mainOrder.getTotalAmount());
            result.put("wechatPayParams", wxPayParams); // 新增：返回微信支付参数
            result.put("message", "支付请求成功");
            return result;

        } catch (Exception e) {
            log.error("创建微信支付失败", e);
            Map<String, Object> result = new LinkedHashMap<>();
            result.put("success", false);
            result.put("message", "创建支付失败：" + e.getMessage());
            return result;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handlePaySuccess(String orderNo) {
        log.info("========== 开始处理支付成功，订单号：{} ==========", orderNo);

        // 查找主订单
        MainOrder mainOrder = orderMapper.selectOne(
            Wrappers.<MainOrder>lambdaQuery().eq(MainOrder::getOrderNo, orderNo)
        );
        if (mainOrder == null) {
            log.error("支付回调：找不到订单，订单号：{}", orderNo);
            return;
        }

        log.info("找到订单: id={}, orderNo={}, payStatus={}, orderStatus={}, businessId={}",
            mainOrder.getId(), mainOrder.getOrderNo(), mainOrder.getPayStatus(), mainOrder.getOrderStatus(), mainOrder.getBusinessId());

        // 防重复处理
        if (mainOrder.getPayStatus() != null && mainOrder.getPayStatus() == 1) {
            log.info("订单已处理过支付成功，跳过，订单号：{}", orderNo);
            return;
        }

        // 更新主订单状态
        mainOrder.setPayStatus(1); // 已支付
        mainOrder.setOrderStatus(1); // 已完成
        mainOrder.setPaidAmount(mainOrder.getTotalAmount());
        orderMapper.updateById(mainOrder);
        log.info("主订单状态已更新为已支付，订单号：{}", orderNo);

        // 更新结算单状态
        CsOrderCard orderCard = baseMapper.selectById(mainOrder.getBusinessId());
        if (orderCard != null) {
            log.info("找到结算单: id={}, status={}, sessionId={}", orderCard.getId(), orderCard.getStatus(), orderCard.getSessionId());
            orderCard.setStatus("paid");
            orderCard.setPayTime(LocalDateTime.now());
            baseMapper.updateById(orderCard);
            log.info("结算单状态已更新为已支付，结算单ID：{}", orderCard.getId());

            // 同步更新聊天消息的payload状态
            if (orderCard.getMsgId() != null) {
                CsMessage msg = messageMapper.selectById(orderCard.getMsgId());
                if (msg != null && StringUtils.isNotBlank(msg.getPayload())) {
                    try {
                        Map<String, Object> payload = JSONUtil.toBean(msg.getPayload(), Map.class);
                        payload.put("status", "paid");
                        msg.setPayload(JSONUtil.toJsonStr(payload));
                        messageMapper.updateById(msg);
                    } catch (Exception e) {
                        log.warn("更新消息payload状态失败: {}", e.getMessage());
                    }
                }
            }

            log.info("支付成功处理完成，订单号：{}，结算单ID：{}", orderNo, orderCard.getId());
        }

        // 支付成功后给学员发送通知消息
        if (mainOrder.getBuyerId() != null && mainOrder.getBuyerType() != null && mainOrder.getBuyerType() == 2) {
            try {
                String orderName = (orderCard != null && orderCard.getOrderName() != null) ? orderCard.getOrderName() : "测评服务";
                mainMessageService.sendNotification(mainOrder.getBuyerId(), "支付成功", "您已成功支付：" + orderName, null);
            } catch (Exception e) {
                log.warn("支付成功后发送通知消息失败: {}", e.getMessage());
            }
        }
    }





    private String generateOrderNo() {
        return "ORD" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomNumbers(4);
    }

    private BigDecimal defaultAmount(BigDecimal amount) {
        return amount == null ? BigDecimal.ZERO : amount;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CsOrderCardVo autoCreateForAssessment(Long sessionId, Long studentId, String orderName, BigDecimal orderPrice, String orderType) {
        // 检查该会话是否已有待支付的结算单，避免重复创建
        CsOrderCard existing = baseMapper.selectOne(Wrappers.<CsOrderCard>lambdaQuery()
            .eq(CsOrderCard::getSessionId, sessionId)
            .eq(CsOrderCard::getStatus, "pending")
            .last("LIMIT 1"));
        if (existing != null) {
            CsOrderCardVo vo = converter.convert(existing, CsOrderCardVo.class);
            if (vo != null) {
                vo.setOrderCardId(existing.getId());
                // 从关联消息获取 senderType
                if (existing.getMsgId() != null) {
                    CsMessage existingMsg = messageMapper.selectById(existing.getMsgId());
                    if (existingMsg != null) {
                        vo.setSenderType(existingMsg.getSenderType());
                    }
                }
                if ("pending".equals(vo.getStatus())) {
                    long seconds = Duration.between(LocalDateTime.now(), existing.getExpireTime()).getSeconds();
                    vo.setCountdownSeconds(Math.max(0, seconds));
                }
            }
            return vo;
        }

        // 从会话获取tenantId、测评价格（结算单本质上是针对测评的）
        String tenantId = "000000";
        BigDecimal resolvedPrice = orderPrice; // 默认使用前端传入的价格
        CsSession session = sessionMapper.selectById(sessionId);
        if (session != null && StringUtils.isNotBlank(session.getSourceId())) {
            String sourceId = session.getSourceId();
            if (sourceId.startsWith("assessment_")) {
                // 测评入口
                try {
                    Long evalId = Long.parseLong(sourceId.substring("assessment_".length()));
                    MainExamEvaluation evaluation = examEvaluationMapper.selectById(evalId);
                    if (evaluation != null) {
                        if (evaluation.getPositionId() != null) {
                            MainPosition position = mainPositionMapper.selectById(evaluation.getPositionId());
                            if (position != null && StringUtils.isNotBlank(position.getTenantId())) {
                                tenantId = position.getTenantId();
                            }
                        }
                        // 前端没传价或传了0时，用测评自身的price
                        if ((resolvedPrice == null || resolvedPrice.compareTo(BigDecimal.ZERO) <= 0)
                                && evaluation.getPrice() != null && evaluation.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                            resolvedPrice = evaluation.getPrice();
                        }
                    }
                } catch (Exception e) { log.warn("从测评获取信息失败: {}", e.getMessage()); }
            } else if (sourceId.startsWith("job_")) {
                // 岗位入口 → 从岗位关联的测评获取价格
                try {
                    Long posId = Long.parseLong(sourceId.substring("job_".length()));
                    MainPosition position = mainPositionMapper.selectById(posId);
                    if (position != null) {
                        if (StringUtils.isNotBlank(position.getTenantId())) {
                            tenantId = position.getTenantId();
                        }
                        // 查找该岗位下第一个有效测评的价格
                        if ((resolvedPrice == null || resolvedPrice.compareTo(BigDecimal.ZERO) <= 0)) {
                            List<MainExamEvaluation> evals = examEvaluationMapper.selectList(
                                Wrappers.<MainExamEvaluation>lambdaQuery()
                                    .eq(MainExamEvaluation::getPositionId, posId)
                                    .eq(MainExamEvaluation::getStatus, "1")
                                    .last("LIMIT 1"));
                            if (!evals.isEmpty()) {
                                MainExamEvaluation firstEval = evals.get(0);
                                if (firstEval.getPrice() != null && firstEval.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                                    resolvedPrice = firstEval.getPrice();
                                }
                                if (StringUtils.isBlank(orderName)) {
                                    orderName = firstEval.getEvaluationName() + "-测评服务费";
                                }
                            }
                        }
                    }
                } catch (Exception e) { log.warn("从岗位获取信息失败: {}", e.getMessage()); }
            }
        }

        // 创建消息（自动创建结算单，有客服时以客服身份，否则以系统身份）
        CsMessage message = new CsMessage();
        message.setSessionId(sessionId);
        message.setMsgNo("ORDER_" + System.currentTimeMillis());
        message.setMsgType("order_card");
        Long waiterId = session != null ? session.getWaiterId() : null;
        // senderId: 有坐席用坐席ID（客服），没有坐席时以系统身份
        if (waiterId != null) {
            message.setSenderId(waiterId);
            message.setSenderType(2); // 客服
        } else {
            message.setSenderId(0L);
            message.setSenderType(3); // 系统
        }
        message.setStatus(1);
        message.setIsRead(0);
        message.setSendTime(LocalDateTime.now());
        messageMapper.insert(message);

        // 创建结算单（价格使用解析后的resolvedPrice，兜底0.01）
        BigDecimal finalPrice = (resolvedPrice != null && resolvedPrice.compareTo(BigDecimal.ZERO) > 0) ? resolvedPrice : new BigDecimal("0.01");
        CsOrderCard orderCard = new CsOrderCard();
        orderCard.setMsgId(message.getId());
        orderCard.setSessionId(sessionId);
        orderCard.setOrderName(orderName);
        orderCard.setOrderPrice(finalPrice);
        orderCard.setOrderType(orderType);
        orderCard.setTenantId(tenantId);
        orderCard.setStatus("pending");
        orderCard.setExpireTime(LocalDateTime.now().plusMinutes(30)); // 30分钟过期
        orderCard.setCreateTime(LocalDateTime.now());
        baseMapper.insert(orderCard);

        // 回写payload到消息（同时写入price和amount，兼容前后端）
        Map<String, Object> payload = new HashMap<>();
        payload.put("orderCardId", orderCard.getId());
        payload.put("name", orderCard.getOrderName());
        payload.put("amount", orderCard.getOrderPrice().toString());
        payload.put("price", orderCard.getOrderPrice().toString());
        payload.put("status", "pending");
        payload.put("expireTime", orderCard.getExpireTime().toString());
        payload.put("countdownSeconds", 1800);
        message.setPayload(JSONUtil.toJsonStr(payload));
        messageMapper.updateById(message);

        sessionService.updateLastMessage(sessionId, "[结算单]" + orderCard.getOrderName());

        // 通过 WebSocket 广播消息，确保前端实时收到
        CsMessageVo msgVo = new CsMessageVo();
        msgVo.setId(message.getId());
        msgVo.setSessionId(message.getSessionId());
        msgVo.setMsgNo(message.getMsgNo());
        msgVo.setSenderType(message.getSenderType());
        msgVo.setSenderId(message.getSenderId());
        msgVo.setMsgType(message.getMsgType());
        msgVo.setPayload(message.getPayload());
        msgVo.setStatus(message.getStatus());
        msgVo.setSendTime(message.getSendTime());
        // 设置 senderRole，确保前端正确识别发送者
        if (message.getSenderType() == 2) {
            msgVo.setSenderRole("waiter");
        } else if (message.getSenderType() == 3) {
            msgVo.setSenderRole("system");
        } else {
            msgVo.setSenderRole("user");
        }
        messagingTemplate.convertAndSend("/topic/session/" + sessionId, msgVo);
        // 通知坐席
        if (session != null && session.getWaiterId() != null) {
            messagingTemplate.convertAndSendToUser(
                session.getWaiterId().toString(),
                "/queue/notify",
                msgVo
            );
        }

        CsOrderCardVo vo = converter.convert(orderCard, CsOrderCardVo.class);
        if (vo != null) {
            vo.setOrderCardId(orderCard.getId());
            vo.setSenderType(message.getSenderType());
            vo.setCountdownSeconds(1800L);
        }
        return vo;
    }


}
