package com.bizzan.bitrade.socket.ws;

import java.math.BigDecimal;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
//import com.binance.connector.client.impl.WebsocketClientImpl;
import com.bizzan.bitrade.engine.ContractCoinMatchFactory;
import com.bizzan.bitrade.engine.TradingAccountMonitor;
import com.bizzan.bitrade.entity.CoinThumb;
import com.bizzan.bitrade.entity.KLine;
import com.bizzan.bitrade.entity.Poke;
import com.bizzan.bitrade.entity.TradePlateItem;
import com.bizzan.bitrade.job.ExchangePushJob;
import com.bizzan.bitrade.service.ContractMarketService;
import com.bizzan.bitrade.service.KLineService;
import com.bizzan.bitrade.util.ZipUtils;

public class WebSocketBinance {
	
	private Logger logger = LoggerFactory.getLogger(WebSocketBinance.class);
	
	public static String DEPTH = "%s@depth10"; // 深度
    public static String KLINE = "%s@kline_%s"; // K线
    public static String DETAIL = "%s@miniTicker"; // 市场概要（最新价格、成交量等）
    public static String TRADE = "%s@trade"; // 成交明细
    
    public static String PERIOD[] = { "1m", "5m", "15m", "30m", "1h","4h", "1d", "1M", "1w" };
	private Map<String, String> periodMap = new HashMap<String, String>();
	public static String URI = "wss://fstream.binance.com";
    
	private ContractCoinMatchFactory matchFactory;
    private TradingAccountMonitor tradingAccountMonitor;
    private ExchangePushJob exchangePushJob;
    private KLineService kLineService;
    //private WebsocketClientImpl client;
    
    private ArrayList<String> depthStreams;
    
    private void initPeriodMap() {
    	periodMap.put("1m", "1min");
    	periodMap.put("5m", "5min");
    	periodMap.put("15m", "15min");
    	periodMap.put("30m", "30min");
    	periodMap.put("1h", "60min");
    	periodMap.put("4h", "4hour");
    	periodMap.put("1d", "1day");
    	periodMap.put("1M", "1mon");
    	periodMap.put("1w", "1week");
    }

	public WebSocketBinance(ContractCoinMatchFactory matchFactory, TradingAccountMonitor tradingAccountMonitor, ExchangePushJob pushJob, ContractMarketService marketService, KLineService kLineService) {
		initPeriodMap();
		
		//client = new WebsocketClientImpl(URI);
        this.matchFactory = matchFactory;
        this.exchangePushJob = pushJob;
        this.tradingAccountMonitor = tradingAccountMonitor;
        this.kLineService = kLineService;
        
        ArrayList<String> tickerStreams = new ArrayList<>();
        ArrayList<String> klineStreams = new ArrayList<>();
        depthStreams = new ArrayList<>();
        ArrayList<String> tradeStreams = new ArrayList<>();
        
        String tickerTopic = "!ticker@arr";
    	tickerStreams.add(tickerTopic);
        
        if (null != this.matchFactory.getMatchMap() && this.matchFactory.getMatchMap().size() > 0) {
            for(String symbol : this.matchFactory.getMatchMap().keySet()) {
            	//String tickerTopic = String.format(DETAIL, symbol.replace("/", "").toLowerCase());
            	//tickerStreams.add(tickerTopic);
            	
            	/*for(String period : periodMap.keySet()) {
            		String klineTopic = String.format(KLINE, symbol.replace("/", "").toLowerCase(), period);
            		klineStreams.add(klineTopic);
            	}*/
            	
            	String depthTopic = String.format(DEPTH, symbol.replace("/", "").toLowerCase());
            	depthStreams.add(depthTopic);
            	
            	/*String tradeTopic = String.format(TRADE, symbol.replace("/", "").toLowerCase());
            	tradeStreams.add(tradeTopic);*/
            }
        }
        
        //connectTicker();
        //connectDepth();
        
        //WebsocketClientImpl client2 = new WebsocketClientImpl(uri);
        /*int klineStreamID = client.combineStreams(klineStreams, ((event) -> {
        	JSONObject returnObj = JSONObject.parseObject(event);
        	if(!returnObj.containsKey("data"))
        		return;
        	JSONObject klineObj = returnObj.getJSONObject("data").getJSONObject("k");
            
            String symbol = klineObj.getString("s").replace("USDT", "/USDT");
            BigDecimal open = klineObj.getBigDecimal("o"); // 收盘价
            BigDecimal close = klineObj.getBigDecimal("c"); // 收盘价
            BigDecimal high = klineObj.getBigDecimal("h"); // 收盘价
            BigDecimal low = klineObj.getBigDecimal("l"); // 收盘价
            BigDecimal vol = klineObj.getBigDecimal("v"); // 收盘价
            BigDecimal q = klineObj.getBigDecimal("q");
            int n = klineObj.getInteger("n");
            String period = periodMap.get(klineObj.getString("i"));
            long time = klineObj.getLongValue("t") / 1000;
            
            //if(klineObj.getString("i").equals("1d"))
            //	logger.info("获取K线：symbol" + " - " + symbol + ", period=" + period+",time="+time);


            KLine kline = new KLine(period);
            kline.setClosePrice(close);
            kline.setCount(n);
            kline.setHighestPrice(high);
            kline.setLowestPrice(low);
            kline.setOpenPrice(open);
            kline.setTime(time);
            kline.setTurnover(vol);
            kline.setVolume(q);
            if(klineObj.getBoolean("x")) {
            	//logger.info("保存K线：{}, symbol-{}", close, symbol);
            	marketService.saveKLine(symbol, kline);
            	kline.setLast(true);
            	
            }
            
            if(period.equals("1min")) {
            	//logger.info("K线最新价：{}, symbol-{}", close, symbol);
            }
            
            // 推送K线(如果只有一条，说明是最新的K线，需要推送到前端K线)
            //logger.info("K线推送：" + kline.getPeriod() + " - " + symbol + " - " + new java.util.Date(kline.getTime()*1000));
            //exchangePushJob.pushTickKline(symbol, kline);
            
        }));*/
        
        
        
        //int tradeStreamID = client.combineStreams(tradeStreams, ((event) -> {
        	
        //}));
    }
	
	/*public void connectTicker() {
		int tickerStreamID = client.allMiniTickerStream(msg->{}, ((event) -> {
        	//logger.info("event={}", event);
        	long time = System.currentTimeMillis()/1000;
        	JSONArray dataArray = JSONArray.parseArray(event);
        	dataArray.forEach(dataObj -> {
		    	JSONObject detailObj = (JSONObject)dataObj;
	        	String symbol = detailObj.getString("s").replace("USDT", "/USDT");
	        	if(!this.matchFactory.containsContractCoinMatch(symbol))
	        		return;
	            BigDecimal open = detailObj.getBigDecimal("o");
	            BigDecimal close = detailObj.getBigDecimal("c");
	            BigDecimal high = detailObj.getBigDecimal("h");
	            BigDecimal low = detailObj.getBigDecimal("l");
	            BigDecimal vol = detailObj.getBigDecimal("v");
	            BigDecimal quantity = detailObj.getBigDecimal("q");
	
	            CoinThumb thumb = new CoinThumb();
	            thumb.setOpen(open);
	            thumb.setClose(close);
	            thumb.setHigh(high);
	            thumb.setLow(low);
	            thumb.setVolume(vol); // 成交量
	            thumb.setTurnover(quantity); // 成交额
	            thumb.setTime(time);
	            //Random r = new Random();
	            //int i = r.nextInt(2);
	            //if(i==1)
	            this.kLineService.updateThumb(symbol, thumb);
	            this.matchFactory.getContractCoinMatch(symbol).refreshThumb(thumb);
	
	            // 委托触发 or 爆仓
	            this.matchFactory.getContractCoinMatch(symbol).refreshPrice(close);
	        	});
		}), msg->{
			logger.info("ticker websocket closed");
			//connectTicker();
		}, msg-> {
			logger.info("ticker websocket failed");
			connectTicker();
		});
	}
	
	public void connectDepth() {
		int depthStreamID = client.combineStreams(depthStreams, msg->{}, ((event) -> {
        	JSONObject returnObj = JSONObject.parseObject(event);
        	if(!returnObj.containsKey("data"))
        		return;
        	JSONObject plateObj = returnObj.getJSONObject("data");
        	String symbol = plateObj.getString("s").replace("USDT", "/USDT");
        	
            // 买盘深度
            JSONArray bids = plateObj.getJSONArray("b");
            List<TradePlateItem> buyItems = new ArrayList<>();
            for(int i = 0; i < bids.size(); i++) {
                TradePlateItem item = new TradePlateItem();
                JSONArray itemObj = bids.getJSONArray(i);
                item.setPrice(itemObj.getBigDecimal(0));
                item.setAmount(itemObj.getBigDecimal(1));
                buyItems.add(item);
            }

            // 卖盘深度
            JSONArray asks = plateObj.getJSONArray("a");
            List<TradePlateItem> sellItems = new ArrayList<>();
            for(int i = 0; i < asks.size(); i++) {
                TradePlateItem item = new TradePlateItem();
                JSONArray itemObj = asks.getJSONArray(i);
                item.setPrice(itemObj.getBigDecimal(0));
                item.setAmount(itemObj.getBigDecimal(1));
                sellItems.add(item);
            }
            // 刷新盘口数据
            this.matchFactory.getContractCoinMatch(symbol).refreshPlate(buyItems, sellItems);
        }), msg->{
			logger.info("depth websocket closed");
        	//connectDepth();
        }, msg->{
			logger.info("depth websocket failed");
        	connectDepth();
        });
	}*/

}
