package com.kym.service.impl;

import com.kym.entity.*;
import com.kym.entity.awoara.OrderInfo;
import com.kym.service.*;
import com.kym.service.cache.KymCache;
import com.kym.service.factory.DiscountStrategyFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 订单结算服务实现
 *
 * @author skyline
 */
@Slf4j
@Service
public class OrderSettlementServiceImpl implements OrderSettlementService {

    @Value("${kym.domain}")
    private String DOMAIN;
    private final WashOrderService washOrderService;
    private final WalletDetailService walletDetailService;
    private final AccountService accountService;
    private final SplitRecordService splitRecordService;
    private final PayLogService payLogService;
    private final UserService userService;
    private final MpMsgTemplateService mpMsgTemplateService;
    private final ParkingCouponRecordService parkingCouponRecordService;

    public OrderSettlementServiceImpl(WashOrderService washOrderService, WalletDetailService walletDetailService,
                                      AccountService accountService, SplitRecordService splitRecordService,
                                      PayLogService payLogService, UserService userService,
                                      MpMsgTemplateService mpMsgTemplateService,
                                      ParkingCouponRecordService parkingCouponRecordService) {
        this.washOrderService = washOrderService;
        this.walletDetailService = walletDetailService;
        this.accountService = accountService;
        this.splitRecordService = splitRecordService;
        this.payLogService = payLogService;
        this.userService = userService;
        this.mpMsgTemplateService = mpMsgTemplateService;
        this.parkingCouponRecordService = parkingCouponRecordService;
    }

    @Override
    @Transactional
    public void settleOrder(WashOrder washOrder, OrderInfo orderInfo) {
        log.info("执行订单结算，订单：{}，结算信息：{}", orderInfo.getOrder_id(), orderInfo);

        // 幂等门闩：条件更新占位（未支付 → 已支付），并发结算时第二个事务更新 0 行直接跳过
        boolean claimed = washOrderService.lambdaUpdate()
                .eq(WashOrder::getId, washOrder.getId())
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
                .set(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
                .update();
        if (!claimed) {
            log.warn("订单：{}，已结算，跳过重复结算", orderInfo.getOrder_id());
            return;
        }

        int rechargePayment;
        int grantsPayment = 0;
        var account = accountService.lambdaQuery().eq(Account::getUserId, washOrder.getUserId()).last("FOR UPDATE").one();
        int amountReceived = orderInfo.getAmount_received();
        if (account.getRechargeBalance() >= amountReceived) {
            rechargePayment = amountReceived;
            accountService.lambdaUpdate()
                    .setSql("balance = balance - {0}, recharge_balance = recharge_balance - {1}",
                            amountReceived, rechargePayment)
                    .eq(Account::getUserId, washOrder.getUserId())
                    .update();
        } else {
            rechargePayment = account.getRechargeBalance();
            grantsPayment = amountReceived - account.getRechargeBalance();
            accountService.lambdaUpdate()
                    .setSql("balance = balance - {0}, recharge_balance = 0, grants_balance = grants_balance - {1}",
                            amountReceived, grantsPayment)
                    .eq(Account::getUserId, washOrder.getUserId())
                    .update();
        }

        washOrder
                .setCloseType(orderInfo.getClose_type())
                .setAmount(orderInfo.getAmount())
                .setAmountReceivable(orderInfo.getAmount_receivable())
                .setAmountReceived(amountReceived)
                .setDiscountMoney(orderInfo.getDiscount_money())
                .setDetail(orderInfo.getDetail())
                .setEndTime(LocalDateTime.now())
                .setTotalSeconds(Duration.between(washOrder.getStartTime(), LocalDateTime.now()).toSeconds())
                .setRechargePayment(rechargePayment)
                .setGrantsPayment(grantsPayment)
                .setPayStatus(WashOrder.PAY_STATUS_已支付)
                .setOrderStatus(WashOrder.ORDER_STATUS_成功);

        washOrderService.updateById(washOrder);

        ensureUserStationBelonging(washOrder.getUserId(), washOrder.getStationId());
        backfillUnattributedRecharges(washOrder.getUserId());

        if (orderInfo.getAmount() == 0) {
            return;
        }

        if (washOrder.getIsCross()) {
            doCrossSplit(washOrder, KymCache.INSTANCE.getUserStationId(washOrder.getUserId()));
        } else {
            doLocalSplit(washOrder);
        }

        var walletDetail = new WalletDetail();
        walletDetail.setUserId(washOrder.getUserId());
        walletDetail.setType(WalletDetail.TYPE_消费);
        walletDetail.setOrderNo(washOrder.getOrderId());
        walletDetail.setAmount(amountReceived);
        walletDetail.setGrantsAmount(grantsPayment);
        walletDetail.setBeforeBalance(account.getBalance());
        walletDetail.setAfterBalance(account.getBalance() - amountReceived);
        walletDetail.setBeforeGrantsBalance(account.getGrantsBalance());
        walletDetail.setAfterGrantsBalance(account.getGrantsBalance() - grantsPayment);
        walletDetail.setTransactionId(washOrder.getId().toString());
        walletDetail.setTransactionTime(LocalDateTime.now());
        walletDetail.setStatus(WalletDetail.STATUS_已确认);
        walletDetailService.save(walletDetail);

        DiscountStrategyFactory.getDiscountStrategy(washOrder.getDiscountType()).computeDiscount(washOrder, account);

        washOrderService.updateById(washOrder);

        if (orderInfo.getAmount() >= KymCache.INSTANCE.getParkingCouponMinAmountByStationId(washOrder.getStationId())) {
            var parkingCouponUrl = KymCache.INSTANCE.getParkingQrCodeUrlByStationId(washOrder.getStationId());
            var code = UUID.randomUUID().toString();
            KymCache.INSTANCE.setParkingCouponCode(code, parkingCouponUrl, 3600 * 2L);
            parkingCouponRecordService.save(new ParkingCouponRecord()
                    .setCode(code)
                    .setUserId(washOrder.getUserId())
                    .setStationId(washOrder.getStationId())
                    .setOrderId(washOrder.getOrderId())
                    .setTargetUrl(parkingCouponUrl)
                    .setStatus(ParkingCouponRecord.STATUS_未使用)
                    .setExpireTime(LocalDateTime.now().plusHours(2)));
            var url = DOMAIN + "/api/parking-coupon?code=" + code;
            mpMsgTemplateService.sendParkingCouponMsg(washOrder, url);
        } else {
            mpMsgTemplateService.sendOrderCompletedMsg(washOrder, account.getBalance());
        }
    }

    @Transactional
    protected void doLocalSplit(WashOrder washOrder) {
        log.info("订单：{}，本店消费，V2方案无需分账", washOrder.getOrderId());
    }

    @Transactional
    protected void doCrossSplit(WashOrder washOrder, String userStationId) {
        int rechargePayment = washOrder.getRechargePayment();
        int grantsPayment = washOrder.getGrantsPayment();
        int totalPayment = rechargePayment + grantsPayment;
        if (totalPayment == 0) {
            log.info("订单：{}，支付金额为0，不产生跨店转账", washOrder.getOrderId());
            return;
        }
        BigDecimal crossRate = new BigDecimal("0.7");
        int crossAmount = crossRate.multiply(BigDecimal.valueOf(totalPayment)).setScale(0, RoundingMode.DOWN).intValue();
        log.info("订单：{}，执行跨店分账，归属站：{}，消费站：{}，充值款实收：{}，赠款实收：{}，转账金额：{}",
                washOrder.getOrderId(), userStationId, washOrder.getStationId(), rechargePayment, grantsPayment, crossAmount);

        var crossExpend = new SplitRecord()
                .setFromStationId(userStationId)
                .setToStationId(washOrder.getStationId())
                .setTradeNo(washOrder.getOrderId())
                .setAmount(crossAmount)
                .setType(SplitRecord.TYPE_CROSS_EXPEND);

        var crossIncome = new SplitRecord()
                .setFromStationId(userStationId)
                .setToStationId(washOrder.getStationId())
                .setTradeNo(washOrder.getOrderId())
                .setAmount(crossAmount)
                .setType(SplitRecord.TYPE_CROSS_INCOME);

        splitRecordService.saveBatch(List.of(crossExpend, crossIncome));
        log.info("订单：{}，跨店分账完成", washOrder.getOrderId());
    }

    /**
     * 兜底保障：如果 createOrder 的自动归属没有生效，在结算时补齐。
     * IoT 回调路径没有用户 Session，同步写 Redis 缓存供后续使用。
     */
    private void ensureUserStationBelonging(Long userId, String orderStationId) {
        var user = userService.getById(userId);
        if (user == null || user.getStationId() != null) {
            return;
        }
        userService.lambdaUpdate()
                .set(User::getStationId, orderStationId)
                .eq(User::getId, userId)
                .update();
        KymCache.INSTANCE.putUserId2StationId(Map.of(userId, orderStationId));
        log.info("兜底归属：用户={} 归属站点={}", userId, orderStationId);
    }

    private void backfillUnattributedRecharges(Long userId) {
        var userStationId = KymCache.INSTANCE.getUserStationId(userId);
        if (userStationId == null) {
            var user = userService.getById(userId);
            userStationId = user != null ? user.getStationId() : null;
        }
        if (userStationId == null) {
            return;
        }

        var walletDetails = walletDetailService.lambdaQuery()
                .eq(WalletDetail::getUserId, userId)
                .eq(WalletDetail::getType, WalletDetail.TYPE_充值)
                .eq(WalletDetail::getStatus, WalletDetail.STATUS_已确认)
                .list();

        if (walletDetails.isEmpty()) {
            return;
        }

        var outTradeNos = walletDetails.stream().map(WalletDetail::getOrderNo).toList();
        var payLogs = payLogService.lambdaQuery().in(PayLog::getOutTradeNo, outTradeNos).list();
        if (payLogs.isEmpty()) {
            return;
        }

        var allTxIds = payLogs.stream().map(PayLog::getTransactionId).collect(Collectors.toSet());
        var existingTxIds = splitRecordService.lambdaQuery()
                .in(SplitRecord::getTradeNo, allTxIds)
                .eq(SplitRecord::getType, SplitRecord.TYPE_RECHARGE)
                .list()
                .stream()
                .map(SplitRecord::getTradeNo)
                .collect(Collectors.toSet());

        for (var payLog : payLogs) {
            if (!existingTxIds.contains(payLog.getTransactionId())) {
                var splitRecord = new SplitRecord()
                        .setFromStationId(userStationId)
                        .setToStationId(userStationId)
                        .setTradeNo(payLog.getTransactionId())
                        .setAmount(payLog.getTotal())
                        .setType(SplitRecord.TYPE_RECHARGE);
                splitRecordService.save(splitRecord);
                log.info("追溯补建充值分账：用户={}, 站点={}, 交易号={}, 金额={}",
                        userId, userStationId, payLog.getTransactionId(), payLog.getTotal());
            }
        }
    }
}
