package com.bizzan.bitrade.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aqmd.netty.annotation.HawkBean;
import com.aqmd.netty.annotation.HawkMethod;
import com.aqmd.netty.common.NettyCacheUtils;
import com.aqmd.netty.push.HawkPushServiceApi;
import com.bizzan.bitrade.constant.NettyCommand;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.netty.QuoteMessage;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.net.SocketAddress;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 处理Netty订阅与取消订阅
 */
@HawkBean
@Slf4j
public class NettyHandler implements MarketHandler {
    @Autowired
    private HawkPushServiceApi hawkPushService;
    private String topicOfSymbol = "CONTRACT_SYMBOL_THUMB";
    private String topicOfPosition = "CONTRACT_POSITION_CHANGE";

    public void subscribeTopic(Channel channel, String topic){
        String userKey = channel.id().asLongText();
        if(!NettyCacheUtils.keyChannelCache.containsKey(channel)) {
            NettyCacheUtils.keyChannelCache.put(channel, userKey);
        }

        NettyCacheUtils.storeChannel(topic,channel);
        if(NettyCacheUtils.userKey.containsKey(userKey)){
            NettyCacheUtils.userKey.get(userKey).add(topic);
        }
        else{
            Set<String> userkeys=new HashSet<>();
            userkeys.add(topic);
            NettyCacheUtils.userKey.put(userKey,userkeys);
        }
    }

    public void unsubscribeTopic(Channel channel,String topic){
        String userKey = channel.id().asLongText();
        if(NettyCacheUtils.userKey.containsKey(userKey)) {
            NettyCacheUtils.userKey.get(userKey).remove(topic);
        }
        NettyCacheUtils.keyChannelCache.remove(channel);
    }

    @HawkMethod(cmd = NettyCommand.CONTRACT_SUBSCRIBE_SYMBOL_THUMB,version = NettyCommand.COMMANDS_VERSION)
    public QuoteMessage.SimpleResponse subscribeSymbolThumb(byte[] body, ChannelHandlerContext ctx){
        QuoteMessage.SimpleResponse.Builder response = QuoteMessage.SimpleResponse.newBuilder();
        subscribeTopic(ctx.channel(),topicOfSymbol);
        response.setCode(0).setMessage("订阅成功");
        return response.build();
    }

    @HawkMethod(cmd = NettyCommand.CONTRACT_UNSUBSCRIBE_SYMBOL_THUMB)
    public QuoteMessage.SimpleResponse unsubscribeSymbolThumb(byte[] body, ChannelHandlerContext ctx){
        QuoteMessage.SimpleResponse.Builder response = QuoteMessage.SimpleResponse.newBuilder();
        unsubscribeTopic(ctx.channel(),topicOfSymbol);
        response.setCode(0).setMessage("取消成功");
        return response.build();
    }

    @HawkMethod(cmd = NettyCommand.CONTRACT_SUBSCRIBE_EXCHANGE)
    public QuoteMessage.SimpleResponse subscribeExchange(byte[] body, ChannelHandlerContext ctx){
        QuoteMessage.SimpleResponse.Builder response = QuoteMessage.SimpleResponse.newBuilder();
        JSONObject json = JSON.parseObject(new String(body));
        String symbol = json.getString("symbol");
        String uid = json.getString("uid");
        if(StringUtils.isNotEmpty(uid)){
            subscribeTopic(ctx.channel(),symbol+"-"+uid);
        }
        subscribeTopic(ctx.channel(),symbol);
        response.setCode(0).setMessage("订阅成功");
        return response.build();
    }

    @HawkMethod(cmd = NettyCommand.CONTRACT_UNSUBSCRIBE_EXCHANGE)
    public QuoteMessage.SimpleResponse unsubscribeExchange(byte[] body, ChannelHandlerContext ctx){
        QuoteMessage.SimpleResponse.Builder response = QuoteMessage.SimpleResponse.newBuilder();
        JSONObject json = JSON.parseObject(new String(body));
        log.info("取消订阅Exchange："+json.toJSONString());
        String symbol = json.getString("symbol");
        String uid = json.getString("uid");
        if(StringUtils.isNotEmpty(uid)){
            unsubscribeTopic(ctx.channel(),symbol+"-"+uid);
        }
        unsubscribeTopic(ctx.channel(), symbol);
        response.setCode(0).setMessage("取消订阅成功");
        return response.build();
    }
    
    @HawkMethod(cmd = NettyCommand.CONTRACT_SUBSCRIBE_POSITION_CHANGE)
    public QuoteMessage.SimpleResponse subscribePositionChange(byte[] body, ChannelHandlerContext ctx){
        QuoteMessage.SimpleResponse.Builder response = QuoteMessage.SimpleResponse.newBuilder();
        String memberId = new String(body);
        log.info("订阅Position："+memberId);
        if(StringUtils.isNotEmpty(memberId)){
            subscribeTopic(ctx.channel(),topicOfPosition+"-"+memberId);
        }
        response.setCode(0).setMessage("订阅成功");
        return response.build();
    }

    @HawkMethod(cmd = NettyCommand.CONTRACT_UNSUBSCRIBE_POSITION_CHANGE)
    public QuoteMessage.SimpleResponse unsubscribePositionChange(byte[] body, ChannelHandlerContext ctx){
        QuoteMessage.SimpleResponse.Builder response = QuoteMessage.SimpleResponse.newBuilder();
        String memberId = new String(body);
        log.info("取消订阅Position："+memberId);
        if(StringUtils.isNotEmpty(memberId)){
            unsubscribeTopic(ctx.channel(),topicOfPosition+"-"+memberId);
        }
        response.setCode(0).setMessage("取消订阅成功");
        return response.build();
    }

    /**
     * 推送最新行情
     * @param symbol
     * @param thumb
     */
    @Override
    public void handleTrade(String symbol, CoinThumb thumb) {
        byte[] body = JSON.toJSONString(thumb).getBytes();
        /*Set<Channel> channelSet = NettyCacheUtils.getChannel(topicOfSymbol);
        if(channelSet!=null) {
        	log.info("channelSet size={}", channelSet.size());
        	for(Channel channel: channelSet) {
        		SocketAddress remoteAddress= channel.remoteAddress();
        		if(remoteAddress!=null && remoteAddress instanceof java.net.InetSocketAddress) {
        			java.net.InetSocketAddress isa = (java.net.InetSocketAddress)remoteAddress;
        			log.info("HostName={}, HostString={}, port={}",isa.getHostName(),isa.getHostString(),isa.getPort());
        		}
        	}
        }*/
        try {
        	hawkPushService.pushMsg(NettyCacheUtils.getChannel(topicOfSymbol),NettyCommand.CONTRACT_PUSH_SYMBOL_THUMB, body);
        } catch (Exception e) {
        	log.info(symbol+"行情推送出错"+e);
        }
    }

    /**
     * 推送成交明细
     * @param symbol
     * @param exchangeTrades
     * @param thumb
     */
    @Override
    public void handleTrades(String symbol, List<ContractTrade> exchangeTrades, CoinThumb thumb) {
        if(exchangeTrades.size() > 0) {
            hawkPushService.pushMsg(NettyCacheUtils.getChannel(symbol), NettyCommand.CONTRACT_PUSH_EXCHANGE_TRADE, JSONObject.toJSONString(exchangeTrades.get(exchangeTrades.size() - 1)).getBytes());
        }
    }

    /**
     * 推送K线
     * @param symbol
     * @param kLine
     */
    @Override
    public void handleKLine(String symbol, KLine kLine) {
        hawkPushService.pushMsg(NettyCacheUtils.getChannel(symbol),NettyCommand.CONTRACT_PUSH_EXCHANGE_KLINE, JSONObject.toJSONString(kLine).getBytes());
    }

    /**
     * 推送盘口
     * @param symbol
     * @param plate
     */
    public void handlePlate(String symbol, TradePlate plate){
        //log.info("推送盘口>>>>>:"+JSON.toJSONString(plate));
        //推送盘口
        hawkPushService.pushMsg(NettyCacheUtils.getChannel(symbol),NettyCommand.CONTRACT_PUSH_EXCHANGE_PLATE, plate.toJSON(24).toJSONString().getBytes());
        //推送深度
        hawkPushService.pushMsg(NettyCacheUtils.getChannel(symbol),NettyCommand.CONTRACT_PUSH_EXCHANGE_DEPTH, plate.toJSON(50).toJSONString().getBytes());
    }

    public void handleOrder(short command, ContractOrderEntrust order){
        try {
            String topic = order.getSymbol() + "-" + order.getMemberId();
            log.info("推送订单:" + JSON.toJSONString(order));
            hawkPushService.pushMsg(NettyCacheUtils.getChannel(topic), command, JSON.toJSONString(order).getBytes());
        }
        catch (Exception e){
            e.printStackTrace();
            log.info("推送出错"+e);
        }
    }
    
    @Override
    public void handlePositionChange(Long memberId) {
    	try {
    		hawkPushService.pushMsg(NettyCacheUtils.getChannel(topicOfPosition+"-"+memberId),NettyCommand.CONTRACT_PUSH_POSITION_CHANGE, memberId.toString().getBytes());
    		log.info("推送仓位变化:" + memberId);
    	}
        catch (Exception e){
            e.printStackTrace();
            log.info("推送仓位变化"+e);
        }
    }
}
