package com.red.circle.other.app.command.team.bd.query;

import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.app.dto.clientobject.team.bd.BdDetailItemCO;
import com.red.circle.other.app.dto.cmd.team.bd.BdDetailsQryCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.mongo.entity.bd.BdLeaderSalarySettlementRecord;
import com.red.circle.other.infra.database.mongo.entity.bd.BdSalarySettlementRecord;
import com.red.circle.other.infra.enums.BdSettlementStatus;
import com.red.circle.tool.core.num.NumUtils;
import com.red.circle.wallet.inner.endpoint.bank.UserBankRunningWaterClient;
import com.red.circle.wallet.inner.endpoint.freight.FreightBalanceRunningWaterClient;
import com.red.circle.wallet.inner.endpoint.salary.UserSalaryAccountClient;
import com.red.circle.wallet.inner.model.cmd.SalaryRunningWaterQueryInnerCmd;
import com.red.circle.wallet.inner.model.cmd.UserBankRunningWaterQryCmd;
import com.red.circle.wallet.inner.model.cmd.UserBankWithdrawMoneyApplyQryCmd;
import com.red.circle.wallet.inner.model.dto.FreightBalanceRunningWaterDTO;
import com.red.circle.wallet.inner.model.dto.SalaryRunningWaterDTO;
import com.red.circle.wallet.inner.model.dto.UserBankRunningWaterDTO;
import com.red.circle.wallet.inner.model.dto.UserBankWithdrawMoneyApplyDTO;
import com.red.circle.wallet.inner.model.enums.SalaryEvent;
import com.red.circle.wallet.inner.model.enums.UserBankWaterEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.util.NumberUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * BD Details 查询执行器
 *
 * @author tf
 * @since 2025-11-17
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class BdDetailsQryExe {

    private final UserSalaryAccountClient userSalaryAccountClient;
    private final MongoTemplate mongoTemplate;
    private final UserProfileGateway userProfileGateway;
    private final UserBankRunningWaterClient userBankRunningWaterClient;
    private final FreightBalanceRunningWaterClient freightBalanceRunningWaterClient;

    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yy/MM/dd HH:mm");

    /**
     * 执行查询
     */
    public List<BdDetailItemCO> execute(BdDetailsQryCmd cmd) {
        List<BdDetailItemCO> allItems = new ArrayList<>();

        // 1. 查询 Wallet 流水记录（Cash out, Transfer, Exchange）
        if (shouldIncludeWalletRecords(cmd.getFilterType())) {
            List<BdDetailItemCO> walletItems = queryWalletRecords(
                    cmd.getReqUserId(), cmd.getFilterType(), cmd.getReqSysOrigin().getOrigin());
            allItems.addAll(walletItems);
        }

        // 2. 批量查询并填充 Transfer 记录的用户信息
        fillTransferUserInfo(allItems);

        // 3. 按时间倒序排序
        allItems.sort((a, b) -> b.getTime().compareTo(a.getTime()));

        return allItems;
    }

    /**
     * 查询钱包流水记录
     */
    private List<BdDetailItemCO> queryWalletRecords(Long userId, String filterType, String sysOrigin) {
        List<BdDetailItemCO> items = new ArrayList<>();

        // 构建查询条件
        SalaryRunningWaterQueryInnerCmd qryCmd = new SalaryRunningWaterQueryInnerCmd();
        qryCmd.setUserId(userId);
        qryCmd.setPageSize(500);

        // 调用 Wallet 服务查询流水
        var response = userSalaryAccountClient.queryRunningWater(qryCmd);
        if (response == null || !response.checkSuccess() || response.getBody() == null) {
            return items;
        }

        PageResult<SalaryRunningWaterDTO> waterList = response.getBody();
        Collection<SalaryRunningWaterDTO> records = waterList.getRecords();

        Set<Long> trackIds = records.stream()
                .filter(e -> "WITHDRAW".equals(e.getSalaryEvent()))
                .filter(e -> StringUtils.hasText(e.getTrackId()))
                .map(e -> Long.valueOf(e.getTrackId())).collect(Collectors.toSet());
        Map<Long, UserBankWithdrawMoneyApplyDTO> applyDTOMap = userBankRunningWaterClient.mapByIds(trackIds).getBody();


        Set<Long> acceptUserIds = records.stream()
                .filter(e -> "SALARY_TRANSFER".equals(e.getSalaryEvent()))
                .map(e -> Long.valueOf(e.getTrackId()))
                .collect(Collectors.toSet());
        Map<Long, FreightBalanceRunningWaterDTO> balanceRunningWaterDTOMap = freightBalanceRunningWaterClient.listByIds(acceptUserIds).getBody()
                .stream().collect(Collectors.toMap(FreightBalanceRunningWaterDTO::getId, e -> e,
                        (v1, v2) -> v1));

        // 转换为 BdDetailItemCO
        for (SalaryRunningWaterDTO water : records) {
            BdDetailItemCO item = convertWalletRecord(water, filterType, applyDTOMap, balanceRunningWaterDTOMap);
            if (item != null) {
                items.add(item);
            }
        }

        return items;
    }

    /**
     * 转换钱包流水记录
     */
    private BdDetailItemCO convertWalletRecord(SalaryRunningWaterDTO water, String filterType,
                                               Map<Long, UserBankWithdrawMoneyApplyDTO> applyDTOMap,
                                               Map<Long, FreightBalanceRunningWaterDTO> balanceRunningWaterDTOMap) {
        String event = water.getSalaryEvent();
        if (event == null) {
            return null;
        }

        // 根据 event 类型判断是否需要包含
        BdDetailItemCO item = new BdDetailItemCO();
        item.setRecordId(water.getId());
        item.setTime(Timestamp.valueOf(water.getCreatedAt()));
        item.setTimeText(TIME_FORMATTER.format(water.getCreatedAt()));

        // Cash out (提现)
        if (SalaryEvent.WITHDRAW.getCode().equals(event)) {
            if (!shouldIncludeType(filterType, "CASH_OUT")) {
                return null;
            }
            UserBankWithdrawMoneyApplyDTO moneyApplyDTO = applyDTOMap.get(Long.parseLong(water.getTrackId()));

            item.setType("CASH_OUT");
            item.setTypeText("Cash out");
            // 提现是支出，金额为负
            item.setAmount(water.getAmount());
            item.setAmountText("-$" + water.getAmount());

            // 根据审批状态设置显示状态
            String displayStatus = "Under review"; // 默认值
            String displayStatusText = "Under review";

            if (moneyApplyDTO != null && moneyApplyDTO.getLatestApprovalStatus() != null) {
                switch (moneyApplyDTO.getLatestApprovalStatus()) {
                    case "SUBMIT":
                        displayStatus = "Under review";
                        displayStatusText = "Under review";
                        break;
                    case "PASS":
                        displayStatus = "Approved";
                        displayStatusText = "Approved";
                        break;
                    case "NOT_PASS":
                        displayStatus = "Rejection";
                        displayStatusText = "Rejection";
                        break;
                    default:
                        // 可选：记录未知状态日志
                        break;
                }
            }

            item.setStatus(displayStatus);
            item.setStatusText(displayStatusText);
            return item;
        }

        // Transfer (转账)
        if (SalaryEvent.SALARY_TRANSFER.getCode().equals(event)) {
            if (!shouldIncludeType(filterType, "TRANSFER")) {
                return null;
            }
            item.setType("TRANSFER");
            item.setTypeText("Transfer");

            FreightBalanceRunningWaterDTO runningWaterDTO = balanceRunningWaterDTOMap.get(Long.parseLong(water.getTrackId()));
            if (runningWaterDTO != null) {
                item.setAmount(runningWaterDTO.getQuantity());
                item.setAmountText("+" + runningWaterDTO.getQuantity() + " coins");
            } else {
                item.setAmount(water.getAmount());
                item.setAmountText("+" + water.getAmount() + " $");
            }
            item.setUserInfo(new BdDetailItemCO.BdDetailUserInfo().setUserId(water.getAcceptUserId()));
            return item;
        }

        // Exchange coins (兑换金币)
        if (SalaryEvent.SALARY_EXCHANGE.getCode().equals(event)) {
            if (!shouldIncludeType(filterType, "EXCHANGE")) {
                return null;
            }
            item.setType("EXCHANGE");
            item.setTypeText("Exchange coins");
            // 兑换是支出，金额为负
            item.setAmount(water.getAmount().negate());
            item.setAmountText("-$" + water.getAmount().toString());
            return item;
        }

        // BD 收入
        if (SalaryEvent.SALARY_BD.getCode().equals(event)) {
            if (!shouldIncludeType(filterType, "BD_SALARY_SETTLEMENT")) {
                return null;
            }
            item.setType("BD_INCOME");
            item.setTypeText("BD's income");
            item.setAmount(water.getAmount());
            item.setAmountText("+$" + water.getAmount().toString());
            return item;
        }

        // BDLEADER 收入
        if (SalaryEvent.SALARY_BD_LEADER.getCode().equals(event)) {
            if (!shouldIncludeType(filterType, "BD_LEADER_SALARY_SETTLEMENT")) {
                return null;
            }
            item.setType("BD_LEADER_INCOME");
            item.setTypeText("BD Leader's income");
            item.setAmount(water.getAmount());
            item.setAmountText("+$" + water.getAmount().toString());
            return item;
        }

        // ADMIN 收入
        if (SalaryEvent.SALARY_ADMIN.getCode().equals(event)) {
            if (!shouldIncludeType(filterType, "ADMIN_SALARY_SETTLEMENT")) {
                return null;
            }
            item.setType("ADMIN_INCOME");
            item.setTypeText("Admin's income");
            item.setAmount(water.getAmount());
            item.setAmountText("+$" + water.getAmount().toString());
            return item;
        }


        return null;
    }

    /**
     * 查询 BD 收入记录
     */
    private List<BdDetailItemCO> queryBdIncomeRecords(Long userId) {
        List<BdDetailItemCO> items = new ArrayList<>();

        // 构建查询条件
        Criteria criteria = Criteria.where("bdUserId").is(userId)
                .and("status").is(BdSettlementStatus.SUCCESS.name());

        Query query = new Query(criteria)
                .with(Sort.by(Sort.Direction.DESC, "createTime"))
                .limit(1000);

        List<BdSalarySettlementRecord> records = mongoTemplate.find(
                query, BdSalarySettlementRecord.class);

        // 转换为 BdDetailItemCO
        for (BdSalarySettlementRecord record : records) {
            BdDetailItemCO item = new BdDetailItemCO();
            item.setRecordId(record.getTimeId());
            item.setType("BD_INCOME");
            item.setTypeText("BD's income");
            item.setAmount(record.getSettlementSalary());
            item.setAmountText("+$" + record.getSettlementSalary().toString());
            item.setTime(record.getCreateTime());
            item.setTimeText(TIME_FORMATTER.format(record.getCreateTime().toLocalDateTime()));
            items.add(item);
        }

        return items;
    }

    /**
     * 查询 BD Leader 收入记录
     */
    private List<BdDetailItemCO> queryBdLeaderIncomeRecords(Long userId) {
        List<BdDetailItemCO> items = new ArrayList<>();

        // 构建查询条件
        Criteria criteria = Criteria.where("bdLeaderUserId").is(userId)
                .and("status").is(BdSettlementStatus.SUCCESS.name());

        Query query = new Query(criteria)
                .with(Sort.by(Sort.Direction.DESC, "createTime"))
                .limit(1000);

        List<BdLeaderSalarySettlementRecord> records = mongoTemplate.find(
                query, BdLeaderSalarySettlementRecord.class);

        // 转换为 BdDetailItemCO
        for (BdLeaderSalarySettlementRecord record : records) {
            BdDetailItemCO item = new BdDetailItemCO();
            item.setRecordId(record.getTimeId());
            item.setType("BD_LEADER_INCOME");
            item.setTypeText("BD Leader's income");
            item.setAmount(record.getSettlementSalary());
            item.setAmountText("+$" + record.getSettlementSalary().toString());
            item.setTime(record.getCreateTime());
            item.setTimeText(TIME_FORMATTER.format(record.getCreateTime().toLocalDateTime()));
            items.add(item);
        }

        return items;
    }

    /**
     * 是否应该包含钱包记录类型
     */
    private boolean shouldIncludeWalletRecords(String filterType) {
        if (filterType == null || filterType.equals("ALL")) {
            return true;
        }
        return filterType.equals("CASH_OUT") || 
               filterType.equals("TRANSFER") || 
               filterType.equals("EXCHANGE");
    }

    /**
     * 是否应该包含指定类型
     */
    private boolean shouldIncludeType(String filterType, String targetType) {
        if (filterType == null || filterType.equals("ALL")) {
            return true;
        }
        return filterType.equals(targetType);
    }

    /**
     * 填充 Transfer 记录的用户信息
     */
    private void fillTransferUserInfo(List<BdDetailItemCO> items) {
        // 收集所有需要查询用户信息的 userId
        Set<Long> userIds = items.stream()
                .filter(item -> item.getUserInfo() != null && item.getUserInfo().getUserId() != null)
                .map(item -> item.getUserInfo().getUserId())
                .collect(Collectors.toSet());

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

        // 批量查询用户信息
        Map<Long, UserProfile> userProfileMap = userProfileGateway.mapByUserIds(userIds);

        // 填充用户信息
        items.stream()
                .filter(item -> item.getUserInfo() != null && item.getUserInfo().getUserId() != null)
                .forEach(item -> {
                    Long userId = item.getUserInfo().getUserId();
                    UserProfile profile = userProfileMap.get(userId);
                    if (profile != null) {
                        item.getUserInfo()
                                .setAccount(profile.getAccount())
                                .setUserNickname(profile.getUserNickname())
                                .setAvatar(profile.getUserAvatar());
                    }
                });
    }

    /**
     * 分页处理
     */
    private PageResult<BdDetailItemCO> paginate(List<BdDetailItemCO> allItems, Integer pageNum, Integer pageSize) {
        if (pageNum == null || pageNum < 1) {
            pageNum = 1;
        }
        if (pageSize == null || pageSize < 1) {
            pageSize = 10;
        }

        int total = allItems.size();
        int start = (pageNum - 1) * pageSize;
        int end = Math.min(start + pageSize, total);

        List<BdDetailItemCO> pageItems = start < total ? 
                allItems.subList(start, end) : new ArrayList<>();

        PageResult<BdDetailItemCO> result = new PageResult<>();
        result.setRecords(pageItems);
        result.setTotal((long) total);
        result.setSize((long) pageSize);
        result.setCurrent((long) pageNum);

        return result;
    }
}
