package com.kym.service.awoara.event.handle;

import com.kym.entity.*;
import com.kym.entity.awoara.MessageBody;
import com.kym.entity.awoara.OrderInfoObject;
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.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * 关闭订单事件（订单结算）
 *
 * @author skyline
 */
@Slf4j
@Component
public class OrderCloseEventHandler implements AwoaraEventHandler<OrderInfoObject> {
    private String DOMAIN;
    private final WashOrderService washOrderService;
    private final WalletDetailService walletDetailService;
    private final AccountService accountService;
    private final StationAccountService stationAccountService;
    private final SplitRecordService splitRecordService;

    private final MpMsgTemplateService mpMsgTemplateService;

    private final StationAccountRecordService stationAccountRecordService;

    public OrderCloseEventHandler(WashOrderService washOrderService, WalletDetailService walletDetailService,
                                  AccountService accountService, StationAccountService stationAccountService,
                                  SplitRecordService splitRecordService,
                                  StationAccountRecordService stationAccountRecordService, MpMsgTemplateService mpMsgTemplateService,
                                    String domain) {
        DOMAIN = domain;
        this.washOrderService = washOrderService;
        this.walletDetailService = walletDetailService;
        this.accountService = accountService;
        this.stationAccountService = stationAccountService;
        this.splitRecordService = splitRecordService;
        this.mpMsgTemplateService = mpMsgTemplateService;
        this.stationAccountRecordService = stationAccountRecordService;
    }


    @Override
    @Transactional
    public void handle(MessageBody<OrderInfoObject> message) {
        log.info("收到订单关闭事件");

        // 订单结算
        var orderInfo = message.getPayload().getData().getOrder_info();
        log.info("订单：{}，结算信息：{}", orderInfo.getOrder_id(), orderInfo);

        // 订单状态、支付状态
        var washOrder = washOrderService.lambdaQuery().eq(WashOrder::getOrderId, orderInfo.getOrder_id()).one();
        if (washOrder == null) {
            log.error("订单不存在，订单号：{}", orderInfo.getOrder_id());
            return;
        }

        int rechargePayment;
        int grantsPayment = 0;
        // 扣款更新余额（优先扣减充值款，不够则扣除赠款），新增资金流水
        var account = accountService.getAccountByUserId(washOrder.getUserId());
        int amount = orderInfo.getAmount();
        if (account.getRechargeBalance() >= amount) {
            rechargePayment = amount;
            accountService.lambdaUpdate()
                    .setSql("balance = balance - {0}, recharge_balance = recharge_balance - {1}",
                            amount, rechargePayment)
                    .eq(Account::getUserId, washOrder.getUserId())
                    .update();
        } else {
            // 充值款余额不足以支付订单，则扣赠款
            rechargePayment = account.getRechargeBalance();
            grantsPayment = amount - account.getRechargeBalance();
            accountService.lambdaUpdate()
                    .setSql("balance = balance - {0}, recharge_balance = 0, grants_balance = grants_balance - {1}",
                            amount, grantsPayment)
                    .eq(Account::getUserId, washOrder.getUserId())
                    .update();
        }

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

        washOrderService.updateById(washOrder);

        // 订单金额为0的订单不处理
        if (orderInfo.getAmount() == 0) {
            return;
        }

        // t_account减（上面已完成）,t_station_account冻结户减,t_station_account商户加，t_split_record记录
        // 需要判断是否跨网点，分开处理；跨网点结算比例是消费站点分订单额的30%，充值站点分70%
        if (washOrder.getIsCross()) {
            // 跨网点订单结算比例是消费站点分订单额的30%，消费站点分70%
            doCrossSplit(washOrder, KymCache.INSTANCE.getUserStationId(washOrder.getUserId()));
        } else {
            // 不跨网点订单结算比例是消费站点分订单额的100%,消费金额*商家消费分润比例30%-消费金额*平台分润10%=消费金额*（商家消费分润比例-平台分润）
            doLocalSplit(washOrder);
        }

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

        // 处理充值权益优惠逻辑/优惠券优惠逻辑/账户优惠金额记录处理逻辑（涉及退款扣减优惠，在NoDiscountHandle中处理）
        DiscountStrategyFactory.getDiscountStrategy(washOrder.getDiscountType()).computeDiscount(washOrder, account);

        // 更新订单优惠金额
        washOrderService.updateById(washOrder);

        // 扣费等资金操作
        deductions(washOrder, account);

        // 判断消费金额是否达标，达标发送领取停车优惠券消息
        if (orderInfo.getAmount() >= WashOrder.PARKING_COUPON_MIN_AMOUNT) {
            var parkingCouponUrl = KymCache.INSTANCE.getParkingQrCodeUrlByStationId(washOrder.getStationId());
            // 维码链接做转换防止重复使用，有效期2小时
            var code = UUID.randomUUID().toString();
            KymCache.INSTANCE.setParkingCouponCode(code, parkingCouponUrl, 3600*2L);
            var url = DOMAIN + "/api/parking-coupon?code=" + code;
            mpMsgTemplateService.sendParkingCouponMsg(washOrder, url);
        } else {
            // 发送公众号消息（订单完成）
            mpMsgTemplateService.sendOrderCompletedMsg(washOrder, account.getBalance());
        }
    }

    /**
     * 扣费等资金操作
     *
     * @param washOrder
     * @param account
     */
    @Transactional
    protected void deductions(WashOrder washOrder, Account account) {
        // 账户扣费
        account.setBalance(account.getBalance() - washOrder.getAmountReceived());
        accountService.updateById(account);

        // 记录资金流水
        var walletDetail = new WalletDetail();
        walletDetail.setUserId(washOrder.getUserId());
        walletDetail.setOrderNo(washOrder.getOrderId());
        // 消费
        walletDetail.setType(WalletDetail.TYPE_消费);
        walletDetail.setAmount(washOrder.getAmountReceivable());
        walletDetail.setTransactionTime(LocalDateTime.now());
        // 已确认
        walletDetail.setStatus(WalletDetail.STATUS_已确认);
        walletDetailService.save(walletDetail);
    }

    /**
     * 执行（本店）分账操作
     *
     * @param washOrder
     */
    @Transactional
    protected void doLocalSplit(WashOrder washOrder) {
        log.info("订单：{}，执行本店分账", washOrder.getOrderId());
        int amount = washOrder.getAmount();
        BigDecimal platformRate = BigDecimal.valueOf(0.1);
        BigDecimal consumeRate = BigDecimal.valueOf(0.3);

        // 平台技术服务费10%
        var platformAmount = platformRate.multiply(BigDecimal.valueOf(amount)).intValue();
        // 解冻金额
        var unfreezeAmount = consumeRate.multiply(BigDecimal.valueOf(amount)).intValue();

        int localAmount = unfreezeAmount - platformAmount;

        // 技术服务费
        var splitRecord0 = new SplitRecord()
                .setFromStationId(washOrder.getStationId())
                .setToStationId(StationAccount.PLATFORM_STATION_ID)
                .setTradeNo(washOrder.getOrderId())
                .setAmount(platformAmount)
                .setType(SplitRecord.TYPE_PLATFORM);

        // 冻结户解冻
        var splitRecord1 = new SplitRecord()
                .setFromStationId(washOrder.getStationId())
                .setToStationId(washOrder.getStationId())
                .setTradeNo(washOrder.getOrderId())
                .setAmount(unfreezeAmount)
                .setType(SplitRecord.TYPE_UNFREEZE);

        // 基本户入账
        var splitRecord2 = new SplitRecord()
                .setFromStationId(washOrder.getStationId())
                .setToStationId(washOrder.getStationId())
                .setTradeNo(washOrder.getOrderId())
                .setAmount(localAmount)
                .setType(SplitRecord.TYPE_CONSUME);

        splitRecordService.saveBatch(List.of(splitRecord0, splitRecord1, splitRecord2));

        // t_station_account_record 0.平台服务费收入 1.归属站点收入 2.归属站点解冻
        var platformStationAccount = stationAccountService.getStationAccount(StationAccount.PLATFORM_STATION_ID);
        var userStationAccount = stationAccountService.getStationAccount(washOrder.getStationId());

        var stationAccountRecord0 = new StationAccountRecord()
                .setStationId(StationAccount.PLATFORM_STATION_ID)
                .setTradeNo(washOrder.getOrderId())
                .setAmount(platformAmount)
                .setType(SplitRecord.TYPE_RECHARGE)
                .setTypeDesc(StationAccountRecord.TYPE_收入)
                .setBeforeBalance(platformStationAccount.getBalance())
                .setAfterBalance(platformStationAccount.getBalance() + platformAmount);

        var stationAccountRecord1 = new StationAccountRecord()
                .setStationId(washOrder.getStationId())
                .setTradeNo(washOrder.getOrderId())
                .setAmount(unfreezeAmount)
                .setType(SplitRecord.TYPE_RECHARGE)
                .setTypeDesc(StationAccountRecord.TYPE_收入)
                .setBeforeBalance(userStationAccount.getBalance())
                .setAfterBalance(userStationAccount.getBalance() + unfreezeAmount);

        stationAccountRecordService.saveBatch(List.of(stationAccountRecord0, stationAccountRecord1));

        // 最后更新账户金额
        stationAccountService.lambdaUpdate()
                .setSql("balance = balance + {0}, frozen_amount = frozen_amount - {1}", unfreezeAmount - platformAmount, unfreezeAmount)
                .eq(StationAccount::getStationId, washOrder.getStationId())
                .update();

        // 平台技术服务费10%
        stationAccountService.lambdaUpdate()
                .setSql("balance = balance + {0}", platformAmount)
                .eq(StationAccount::getId, StationAccount.PLATFORM_ACCOUNT_ID)
                .eq(StationAccount::getStationId, StationAccount.PLATFORM_STATION_ID)
                .update();


    }

    /**
     * 执行跨店分账操作
     * 跨店结算比例是消费站点分订单额的70%，充值站点分30%
     * 具体步骤：
     * 1.归属站点解冻消费金额（扣除平台手续费）
     * 2.归属站点支出（订单金额的70%）
     * 3.消费站点收入（订单金额的70%）
     *
     * @param washOrder
     * @param userStationId 用户归属的站点Id
     */
    @Transactional
    protected void doCrossSplit(WashOrder washOrder, String userStationId) {
        log.info("订单：{}，执行跨店分账", washOrder.getOrderId());
        int amount = washOrder.getAmount();
        BigDecimal platformRate = BigDecimal.valueOf(0.1);
        BigDecimal crossRate = BigDecimal.valueOf(0.7);

        // 平台技术服务费10%
        var platformAmount = BigDecimal.valueOf(amount).multiply(platformRate).intValueExact();

        // 解冻金额 = 订单金额
        var unfreezeAmount = amount;

        // 归属站点账户解冻扣除平台技术服务费后总共用于分账的金额
        var localAmount = (int) (unfreezeAmount * 0.3) - platformAmount;

        // 当前消费站点分账收入（订单金额的70%，不承担平台手续费）
        var crossAmount = BigDecimal.valueOf(amount).multiply(crossRate).intValueExact();

        // t_split_record 0.平台服务费收入 1.消费站点收入 2.归属站点解冻 3.归属站点收入 4.归属站点支出（给消费站点结算）
        var splitRecord0 = new SplitRecord()
                .setFromStationId(userStationId)
                .setToStationId(StationAccount.PLATFORM_STATION_ID)
                .setTradeNo(washOrder.getOrderId())
                .setAmount(platformAmount)
                .setType(SplitRecord.TYPE_PLATFORM);

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

        var splitRecord2 = new SplitRecord()
                .setFromStationId(userStationId)
                .setToStationId(washOrder.getStationId())
                .setTradeNo(washOrder.getOrderId())
                .setAmount(unfreezeAmount)
                .setType(SplitRecord.TYPE_UNFREEZE);

        var splitRecord3 = new SplitRecord()
                .setFromStationId(userStationId)
                .setToStationId(userStationId)
                .setTradeNo(washOrder.getOrderId())
                .setAmount(localAmount)
                .setType(SplitRecord.TYPE_CONSUME);

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

        splitRecordService.saveBatch(List.of(splitRecord0, splitRecord1, splitRecord2, splitRecord3, splitRecord4));

        // t_station_account_record 0.平台服务费收入 1.消费站点收入 2.归属站点解冻 3.归属站点收入 4.归属站点支出（给消费站点结算）
        var platformStationAccount = stationAccountService.getStationAccount(StationAccount.PLATFORM_STATION_ID);
        var consumeStationAccount = stationAccountService.getStationAccount(washOrder.getStationId());
        var userStationAccount = stationAccountService.getStationAccount(userStationId);

        // 平台服务费收入
        var stationAccountRecord0 = new StationAccountRecord()
                .setStationId(StationAccount.PLATFORM_STATION_ID)
                .setTradeNo(washOrder.getOrderId())
                .setAmount(platformAmount)
                .setType(SplitRecord.TYPE_PLATFORM)
                .setTypeDesc(StationAccountRecord.TYPE_收入)
                .setBeforeBalance(platformStationAccount.getBalance())
                .setAfterBalance(platformStationAccount.getBalance() + platformAmount);

        // 消费站点收入
        var stationAccountRecord1 = new StationAccountRecord()
                .setStationId(washOrder.getStationId())
                .setTradeNo(washOrder.getOrderId())
                .setAmount(crossAmount)
                .setType(SplitRecord.TYPE_CONSUME)
                .setTypeDesc(StationAccountRecord.TYPE_收入)
                .setBeforeBalance(consumeStationAccount.getBalance())
                .setAfterBalance(consumeStationAccount.getBalance() + crossAmount);

        //归属站点解冻（站点收入）
        var stationAccountRecord2 = new StationAccountRecord()
                .setStationId(userStationId)
                .setTradeNo(washOrder.getOrderId())
                .setAmount(unfreezeAmount)
                .setType(SplitRecord.TYPE_UNFREEZE)
                .setTypeDesc(StationAccountRecord.TYPE_收入)
                .setBeforeBalance(userStationAccount.getBalance())
                .setAfterBalance(userStationAccount.getBalance() + localAmount)
                .setBeforeFrozenAmount(userStationAccount.getFrozenAmount())
                .setAfterFrozenAmount(userStationAccount.getFrozenAmount() - unfreezeAmount);

        // 归属站点收入
//        var stationAccountRecord3 = new StationAccountRecord()
//                .setStationId(userStationId)
//                .setTradeNo(washOrder.getOrderId())
//                .setAmount(localAmount)
//                .setType(SplitRecord.TYPE_CONSUME)
//                .setTypeDesc(StationAccountRecord.TYPE_收入)
//                .setBeforeBalance(userStationAccount.getBalance())
//                .setAfterBalance(userStationAccount.getBalance() + localAmount)
//                .setBeforeFrozenAmount(userStationAccount.getFrozenAmount())
//                .setAfterFrozenAmount(userStationAccount.getFrozenAmount() - unfreezeAmount);


        // 归属站点支出（结算给消费站点）
        var stationAccountRecord4 = new StationAccountRecord()
                .setStationId(userStationId)
                .setTradeNo(washOrder.getOrderId())
                .setAmount(crossAmount)
                .setType(SplitRecord.TYPE_CROSS_EXPEND)
                .setTypeDesc(StationAccountRecord.TYPE_支出)
                .setBeforeBalance(stationAccountRecord2.getAfterBalance())
                .setAfterBalance(stationAccountRecord2.getAfterBalance() - unfreezeAmount);

        stationAccountRecordService.saveBatch(List.of(stationAccountRecord0, stationAccountRecord1, stationAccountRecord2, stationAccountRecord4));

        // 最后更新账户金额
        // 当前消费站点收入（跨店消费，原充值站点要分订单的70%）
        stationAccountService.lambdaUpdate()
                .setSql("balance = balance + {0}", crossAmount)
                .eq(StationAccount::getStationId, washOrder.getStationId())
                .update();

        // 用户归属站点解冻和收入，用户归属站点支出（支付给消费站点）
        stationAccountService.lambdaUpdate()
                .setSql("balance = balance + {0}, frozen_amount = frozen_amount - {1}", localAmount - crossAmount, unfreezeAmount)
                .eq(StationAccount::getStationId, userStationId)
                .update();
    }
}
