package com.market.service;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.market.model.SpotAssetChangeMessage;
import com.market.entity.Account;
import com.market.entity.ExOrder;
import com.market.enums.OrderStatus;
import com.market.manager.SpotClientSessionManager;
import com.market.model.SpotClientSession;
import com.market.model.SpotAssetOrderChangeResp;
import com.market.utils.SpotConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.market.mapper.SpotAccountMapper;
import com.market.mapper.SpotExOrderMapper;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 现货资产/订单变动广播服务
 * <p>
 * 收到 Kafka 消息后，根据 uid 找到对应的 WebSocket 会话，
 * 查询最新资产或订单数据，推送到客户端的 broadcastQueue。
 *
 * @author system
 * @date 2026-05-07
 */
@Service
public class SpotBroadcastService {

    private static final Logger log = LoggerFactory.getLogger(SpotBroadcastService.class);

    /** 单次推送最大订单条数 */
    private static final int MAX_ORDER_LIMIT = 50;

    private final SpotClientSessionManager sessionManager;
    private final SpotAccountMapper        accountMapper;
    private final SpotExOrderMapper        exOrderMapper;
    private final ObjectMapper             objectMapper;

    public SpotBroadcastService(SpotClientSessionManager sessionManager,
                                SpotAccountMapper accountMapper,
                                SpotExOrderMapper exOrderMapper) {
        this.sessionManager = sessionManager;
        this.accountMapper  = accountMapper;
        this.exOrderMapper  = exOrderMapper;
        this.objectMapper   = new ObjectMapper();
    }

    /**
     * 处理资产/订单变动广播
     *
     * @param changeMessage Kafka 消费到的变动消息
     */
    @DS("kucoin")
    public void broadcast(SpotAssetChangeMessage changeMessage) {
        if (changeMessage == null || changeMessage.getUid() == null) {
            return;
        }

        try {
            String uid = String.valueOf(changeMessage.getUid());

            // 1. 找到该用户所有在线 WebSocket 会话
            List<SpotClientSession> sessions = sessionManager.getSessionsByUid(uid);
            if (sessions == null || sessions.isEmpty()) {
                return;
            }

            // 2. 根据变动类型构建响应数据
            SpotAssetOrderChangeResp resp;
            if (SpotAssetChangeMessage.TYPE_ASSET.equals(changeMessage.getType())) {
                resp = buildAssetResp(changeMessage);
            } else if (SpotAssetChangeMessage.TYPE_ORDER.equals(changeMessage.getType())) {
                resp = buildOrderResp(changeMessage);
            } else {
                log.warn("未知资产变动类型: {}", changeMessage.getType());
                return;
            }

            // 3. 序列化并推入每个会话的广播队列
            String json = objectMapper.writeValueAsString(resp);
            for (SpotClientSession session : sessions) {
                session.getBroadcastQueue().offer(json);
            }

        } catch (Exception e) {
            log.error("广播资产/订单变动失败: uid={}, type={}",
                    changeMessage.getUid(), changeMessage.getType(), e);
        }
    }

    // ------------------------------------------------------------------ private

    /**
     * 查询账户资产并构建资产变动响应
     *
     * @param changeMessage 变动消息（含 uid 和 symbols 币种列表）
     * @return 资产变动响应
     */
    private SpotAssetOrderChangeResp buildAssetResp(SpotAssetChangeMessage changeMessage) {
        // 1. 查询账户资产
        LambdaQueryWrapper<Account> wrapper = new LambdaQueryWrapper<Account>()
                .eq(Account::getUid, changeMessage.getUid());

        if (changeMessage.getSymbols() != null && !changeMessage.getSymbols().isEmpty()) {
            List<String> upperSymbols = changeMessage.getSymbols().stream()
                    .map(String::toUpperCase)
                    .collect(Collectors.toList());
            wrapper.in(Account::getSymbol, upperSymbols);
        }

        List<Account> accounts = accountMapper.selectList(wrapper);

        // 2. 转换为 AccountAsset 列表
        List<SpotAssetOrderChangeResp.AccountAsset> assetList = new ArrayList<>();
        for (Account account : accounts) {
            assetList.add(buildAccountAsset(account));
        }

        // 3. 组装响应
        SpotAssetOrderChangeResp resp = new SpotAssetOrderChangeResp();
        resp.setType(SpotAssetChangeMessage.TYPE_ASSET);
        resp.setAccountList(assetList);
        resp.setOrderList(new ArrayList<>());
        return resp;
    }

    /**
     * 查询订单并构建订单变动响应
     *
     * @param changeMessage 变动消息（含 uid 和 symbols 交易对列表）
     * @return 订单变动响应
     */
    private SpotAssetOrderChangeResp buildOrderResp(SpotAssetChangeMessage changeMessage) {
        // 1. 查询活跃订单（待成交/部分成交）
        LambdaQueryWrapper<ExOrder> wrapper = new LambdaQueryWrapper<ExOrder>()
                .eq(ExOrder::getUserId, changeMessage.getUid())
                .in(ExOrder::getStatus,
                        OrderStatus.NEW.getCode(),
                        OrderStatus.PART_FILLED.getCode())
                .orderByDesc(ExOrder::getCtime)
                .last("LIMIT " + MAX_ORDER_LIMIT);

        if (changeMessage.getSymbols() != null && !changeMessage.getSymbols().isEmpty()) {
            List<String> lowerSymbols = changeMessage.getSymbols().stream()
                    .map(String::toLowerCase)
                    .collect(Collectors.toList());
            wrapper.in(ExOrder::getSymbol, lowerSymbols);
        }

        List<ExOrder> orders = exOrderMapper.selectList(wrapper);

        // 2. 查询订单总数
        Long orderCount = exOrderMapper.selectCount(
                new LambdaQueryWrapper<ExOrder>()
                        .eq(ExOrder::getUserId, changeMessage.getUid())
                        .in(ExOrder::getStatus,
                                OrderStatus.NEW.getCode(),
                                OrderStatus.PART_FILLED.getCode()));

        // 3. 转换为 OrderInfo 列表
        List<SpotAssetOrderChangeResp.OrderInfo> orderList = new ArrayList<>();
        for (ExOrder order : orders) {
            orderList.add(buildOrderInfo(order));
        }

        // 4. 组装响应
        SpotAssetOrderChangeResp resp = new SpotAssetOrderChangeResp();
        resp.setType(SpotAssetChangeMessage.TYPE_ORDER);
        resp.setAccountList(new ArrayList<>());
        resp.setOrderList(orderList);
        resp.setOrderCount(orderCount);
        return resp;
    }

    /** 构建 AccountAsset 对象 */
    private SpotAssetOrderChangeResp.AccountAsset buildAccountAsset(Account account) {
        SpotAssetOrderChangeResp.AccountAsset asset = new SpotAssetOrderChangeResp.AccountAsset();
        asset.setSymbol(account.getSymbol());
        BigDecimal available = account.getHotMoney()  != null ? account.getHotMoney()  : BigDecimal.ZERO;
        BigDecimal frozen    = account.getColdMoney() != null ? account.getColdMoney() : BigDecimal.ZERO;
        asset.setAvailable(available);
        asset.setFrozen(frozen);
        asset.setTotal(available.add(frozen));
        return asset;
    }

    /** 构建 OrderInfo 对象 */
    private SpotAssetOrderChangeResp.OrderInfo buildOrderInfo(ExOrder order) {
        SpotAssetOrderChangeResp.OrderInfo info = new SpotAssetOrderChangeResp.OrderInfo();
        info.setOrderId(order.getId());
        info.setSymbol(order.getSymbol());
        info.setSide(order.getSide());
        info.setType(order.getType());
        info.setPrice(order.getPrice());
        info.setVolume(order.getVolume());
        info.setDealVolume(order.getDealVolume());
        info.setStatus(order.getStatus());
        return info;
    }
}
