package com.sonic.lion.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.sonic.common.auth.domains.Session;
import com.sonic.common.rpc.Page;
import com.sonic.daosupport.converter.PageConverter;
import com.sonic.lion.dao.AccountBuffAwaitingDao;
import com.sonic.lion.dao.AccountBuffBillDao;
import com.sonic.lion.domain.entity.AccountBuff;
import com.sonic.lion.domain.entity.AccountBuffBill;
import com.sonic.lion.domain.entity.PayTrade;
import com.sonic.lion.domain.enums.BuffAmountTypeEnum;
import com.sonic.lion.domain.enums.BuffClassifyEnum;
import com.sonic.lion.domain.enums.BuffType;
import com.sonic.lion.domain.enums.InOrOut;
import com.sonic.lion.domain.output.FilterTypeDict;
import com.sonic.lion.domain.req.BillListReq;
import com.sonic.lion.domain.resp.BillOutput;
import com.sonic.lion.domain.resp.SummaryBillListResp;
import com.sonic.lion.enums.BizType;
import com.sonic.lion.enums.PayGenrtatorCodeType;
import com.sonic.lion.service.AccountBuffBillService;
import com.sonic.lion.service.CommonSendMqService;
import com.sonic.lion.service.PayTradeService;
import com.sonic.lion.utils.KeyGenerator;
import com.sonic.lion.utils.NoDisplayBizNumSet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;

/**
 * @author: code
 * @date: 2025/07/17
 * @Description:
 * @version: 1.0.0
 */
@Service
@Slf4j
public class AccountBuffBillServiceImpl extends ServiceImpl<AccountBuffBillDao, AccountBuffBill> implements AccountBuffBillService {

    @Autowired
    private AccountBuffBillDao accountBuffBillDao;
    @Autowired
    private AccountBuffAwaitingDao accountBuffAwaitingDao;
    @Autowired
    private PayTradeService payTradeService;
    @Autowired
    private CommonSendMqService commonSendMqService;
    /**
     * 流水最大的页数
     */
    private final Integer MAX_PAGE_NUM = 500;

    @Override
    public SummaryBillListResp billListSummary(BillListReq req, Session session) {
        //校验分页参数，如果大于500页则不再继续分了
        if (req.getPage().getPn() > MAX_PAGE_NUM) {
            req.getPage().setPn(MAX_PAGE_NUM);
        }
        LambdaQueryWrapper<AccountBuffBill> queryWrapper = Wrappers.<AccountBuffBill>lambdaQuery()
                .eq(AccountBuffBill::getUid, session.getUserId())
                .orderByDesc(AccountBuffBill::getCreateTime);
        if (req.getType() == BillListReq.Type.BALANCE) {
            queryWrapper.eq(AccountBuffBill::getBuffType, BuffType.BALANCE);
        } else if (req.getType() == BillListReq.Type.INCOME) {
            queryWrapper.in(AccountBuffBill::getBuffType, BuffType.WITHDRAWABLE_INCOME, BuffType.AWAITING_INCOME, BuffType.FROZEN_INCOME);
        }
        //只能查询最近1年的数据
        LocalDateTime startTime = LocalDateTime.now().minusYears(1);
        LocalDateTime endTime = LocalDateTime.now();
        if (req.getStartTime() != null) {
            LocalDateTime userStartTime = LocalDateTime.ofEpochSecond(req.getStartTime(), 0, ZoneOffset.ofHours(8));
            if (userStartTime.isAfter(startTime)) {
                startTime = userStartTime;
            }
        }
        if (req.getEndTime() != null) {
            LocalDateTime userEndTime = LocalDateTime.ofEpochSecond(req.getEndTime(), 0, ZoneOffset.ofHours(8));
            if (userEndTime.isBefore(endTime)) {
                endTime = userEndTime;
            }
        }
        queryWrapper.between(AccountBuffBill::getCreateTime, startTime, endTime.plusSeconds(3));

        Page<AccountBuffBill> page = req.getPage();
        IPage<AccountBuffBill> result = page(PageConverter.buildQueryPage(page), queryWrapper);
        Page<BillOutput> pageResult = PageConverter.convert(result, bill -> {
            BillOutput resp = getBillListResp(session, bill);
            return resp;
        });

        SummaryBillListResp resp = summary(req, session.getUserId(), pageResult);
        return resp;
    }

    /**
     * 获取Bill list Resp
     *
     * @param session
     * @param bill
     * @return
     */
    private BillOutput getBillListResp(Session session, AccountBuffBill bill) {
        BillOutput resp = new BillOutput();
        resp.setId(bill.getId());
        resp.setAmount(bill.getBuff());
        resp.setPlatform(bill.getPlatform());
        resp.setTradeNo(bill.getTradeNo());
        //流水item显示名称
        resp.setItem(getItemDesc(bill));
        resp.setTime(bill.getCreateTime());
        resp.setPayment(bill.getPayment());
        //流水Order
        resp.setBizNum(getBizNum(bill));
        resp.setInOrOut(bill.getInOrOut());
        resp.setBizType(bill.getBizType());
        resp.setStatus(bill.getStatus());
        resp.setMessage(bill.getReason());
        resp.setBuffType(bill.getBuffType());
        resp.setExtend(bill.getExtend());

        //待收入转可提现的时间
        if (BuffType.AWAITING_INCOME.equals(bill.getBuffType()) && InOrOut.IN.equals(bill.getInOrOut())) {
            resp.setToWithdrawableIncomeTime(bill.getToWithdrawableIncomeTime());
        }
        return resp;
    }

    /**
     * 获取业务单号
     *
     * @param bill
     * @return
     */
    private String getBizNum(AccountBuffBill bill) {
        if (bill.getBizType() == BizType.REFUND) {
            //退款时如果是退订单打赏则展示关联单号
            return StringUtils.isNotEmpty(bill.getBizNoRelationNo()) ? bill.getBizNoRelationNo() : bill.getBizNo();
        } else {
            //如果业务类型时充值或体现则不返回 交易号
            return NoDisplayBizNumSet.tradeNoSets.contains(bill.getBizType()) ? null : bill.getBizNo();
        }
    }

    private String getItemDesc(AccountBuffBill buffBill) {
        return NoDisplayBizNumSet.getItemDesc(buffBill, false);
    }



    /**
     * 总结
     *
     * @param billListReq
     * @param userId
     * @param page
     * @param excludCharge
     * @return
     */
    @Override
    public SummaryBillListResp summary(BillListReq billListReq, Long userId, Page<BillOutput> page, boolean excludCharge) {
//        LocalDateTime startTime = LocalDateTime.ofEpochSecond(billListReq.getStartTime(), 0, ZoneOffset.ofHours(8));
//        LocalDateTime endTime = LocalDateTime.ofEpochSecond(billListReq.getEndTime(), 0, ZoneOffset.ofHours(8));
//
//        String type = billListReq.getType() == null ? null : billListReq.getType().name();
//        Long totalIncome = 0L;
//        Long totalOutcome = 0L;
//        Integer bizType = null;
//        if (excludCharge) {
//            totalIncome = this.getBaseMapper().sumTotal(startTime, endTime, userId, InOrOut.IN.getValue(), type, "INCOME");
//            totalOutcome = this.getBaseMapper().sumTotal(startTime, endTime, userId, InOrOut.OUT.getValue(), type, "OUTCOME");
//        } else {
//            totalIncome = this.getBaseMapper().sumTotal(startTime, endTime, userId, InOrOut.IN.getValue(), type, null);
//            totalOutcome = this.getBaseMapper().sumTotal(startTime, endTime, userId, InOrOut.OUT.getValue(), type, null);
//        }

        SummaryBillListResp summaryBillListResp = new SummaryBillListResp();
        summaryBillListResp.setIncomeTotal(0L);
        summaryBillListResp.setOutcomeTotal(0L);
        summaryBillListResp.setPageList(page);
        return summaryBillListResp;
    }


    /**
     * 专为 提现写的 bill 表
     * 这个bill表有状态  审核中 , 提现中 , 提现成功 , 提现失败
     *
     * @param input
     * @param accountBuff
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long insertBillWhenWithdraw(PayTrade input, AccountBuff accountBuff) {
        Long total = accountBuff.getBalance() + accountBuff.getWithdrawableIncome() + accountBuff.getAwaitingIncome() + accountBuff.getFrozenIncome();
        //操作后总buff
        //5.19.0 操作后总buff不变只是在 内部流转。
        long afterTotalBuff = total;
        AccountBuffBill bill = AccountBuffBill.builder()
                .platform(input.getPlatform())
                .billNo(KeyGenerator.instance().generatorUniqueKey(PayGenrtatorCodeType.ACCOUNT_BILL))
                .accountId(accountBuff.getId())
                .uid(input.getSrcAccountId())
                .desUid(null)
                .buff(input.getOccurAmount())
                .bizType(input.getBizType())
                .payChannel(input.getPayChannel())
                .tradeNo(input.getTradeNo())
                .bizNo(input.getOutTradeNo())
                .bizNoRelationNo(input.getOutTradeNoRelationNo())
                .balance(afterTotalBuff)
                .inOrOut(InOrOut.OUT)
                .buffType(BuffType.BALANCE)
                .reason(input.getErrorMessage())
                .withdrawStatus(AccountBuffBill.WithdrawStatus.IN_REVIEW)
                .createTime(input.getCreateTime())
                .buffClassify(BuffClassifyEnum.getBuffClassify(input.getBizType(), InOrOut.OUT))
                .build();
        accountBuffBillDao.insert(bill);
        return bill.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertBillWhenWithdrawFail(Long id, AccountBuff accountBuff) {
        AccountBuffBill accountBuffBill = getById(id);
        accountBuffBill.setId(null);
        accountBuffBill.setInOrOut(InOrOut.IN);
        accountBuffBill.setBillNo(KeyGenerator.instance().generatorUniqueKey(PayGenrtatorCodeType.ACCOUNT_BILL));
        accountBuffBill.setReason(null);
        //写入当前用户的余额数据
        accountBuffBill.setBalance(accountBuff.getBalance());
        accountBuffBill.setWithdrawStatus(AccountBuffBill.WithdrawStatus.WITHDRAW_FAIL_BACK);
        accountBuffBill.setBuffClassify(BuffClassifyEnum.getBuffClassify(BizType.WITHDRAW, InOrOut.IN));
        accountBuffBill.setCreateTime(LocalDateTime.now());
        accountBuffBill.setEditTime(LocalDateTime.now());
        accountBuffBillDao.insert(accountBuffBill);
    }

    /**
     * 更新流水状态 和 原因。
     *
     * @param billId
     * @param after
     * @param message
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWithdrawStatus(Long billId, AccountBuffBill.WithdrawStatus after, String message) {
        return accountBuffBillDao.updateWithdrawStatus(billId, after.name(), message) > 0;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWithdrawBillAmount(Long billId, Long amount) {
        return accountBuffBillDao.updateWithdrawBillAmount(billId, amount) > 0;
    }

    /**
     * 获取筛选中Buff Balance Income类型列表
     *
     * @param amountType
     * @return
     */
    private List<FilterTypeDict> getFilterTypeDicList(BuffAmountTypeEnum amountType) {
        List<FilterTypeDict> filterTypeDictList = Lists.newArrayList();
        List<BuffClassifyEnum> buffClassifyList = BuffClassifyEnum.getBuffClassifyList(amountType);
        for (BuffClassifyEnum buffClassifyEnum : buffClassifyList) {
            FilterTypeDict filterTypeDict = new FilterTypeDict();
            filterTypeDict.setCode(buffClassifyEnum.name());
            filterTypeDict.setName(buffClassifyEnum.getDesc());
            filterTypeDictList.add(filterTypeDict);
        }
        return filterTypeDictList;
    }

    @Override
    public void updateBuffTypeToRefund(String tradeNo) {
        List<AccountBuffBill> list = list(Wrappers.<AccountBuffBill>lambdaQuery().eq(AccountBuffBill::getTradeNo, tradeNo).eq(AccountBuffBill::getInOrOut, InOrOut.IN.getValue()).eq(AccountBuffBill::getBuffType, BuffType.AWAITING_INCOME.getValue()));
        for (AccountBuffBill bill : list) {
            //更新为退款类型
            update(Wrappers.<AccountBuffBill>lambdaUpdate()
                    .set(AccountBuffBill::getBuffType, BuffType.REFUND)
                    .eq(AccountBuffBill::getId, bill.getId())
            );
        }
    }

}
