package com.bizzan.bitrade.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bizzan.bitrade.engine.ContractCoinMatch;
import com.bizzan.bitrade.engine.ContractCoinMatchFactory;
import com.bizzan.bitrade.engine.TradingAccountMonitor;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.service.ContractCoinService;
import com.bizzan.bitrade.service.ContractMarketService;
import com.bizzan.bitrade.service.ContractOrderEntrustService;
import com.bizzan.bitrade.service.ContractRewardRecordService;
import com.bizzan.bitrade.service.ExchangeRewardService;
import com.bizzan.bitrade.service.KLineService;
import com.bizzan.bitrade.service.MemberTransactionService;
import com.bizzan.bitrade.service.RedisLock;
import com.bizzan.bitrade.util.DateUtil;
import com.bizzan.bitrade.vo.ContractCoinVo;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.text.ParseException;
import java.time.Instant;
import java.time.ZoneId;
import java.util.*;

@Api(description="合约行情接口(已弃用，行情数据已移到/market/swagger-ui.html#/)")
@Slf4j
@RestController
public class MarketController {

    private Logger logger = LoggerFactory.getLogger(MarketController.class);
    @Autowired
    private ContractCoinService coinService;

    @Autowired
    private ContractCoinMatchFactory contractCoinMatchFactory;

    @Autowired
    private ContractMarketService marketService;
	@Autowired
    private TradingAccountMonitor tradingAccountMonitor;
	@Autowired
	private KLineService kLineService;
    @Autowired
    private RestTemplate restTemplate;
	@Autowired
	private RedisLock redisLock;

    @Autowired
    private ContractOrderEntrustService contractOrderEntrustService;
    @Autowired
    private ContractRewardRecordService contractRewardRecordService;
    @Autowired
    private MemberTransactionService memberTransactionService;
    @Autowired
    private ExchangeRewardService exchangeRewardService;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
	
    /**
     * 获取支持的交易币种
     * @return
     */
    @RequestMapping("symbol")
    public List<ContractCoin> findAllSymbol(){
        List<ContractCoin> coins = coinService.findAllVisible();
        return coins;
    }
    /**
     * 获取币种缩略行情
     * @return
     */
    @RequestMapping("symbol-thumb")
    public List<CoinThumb> findSymbolThumb(){
    	//log.info("symbol-thumb start");
        List<ContractCoin> coins = coinService.findAllVisible();
        List<CoinThumb> thumbs = new ArrayList<>();
        for(ContractCoin coin:coins){
            ContractCoinMatch processor = contractCoinMatchFactory.getContractCoinMatch(coin.getSymbol());
            if(processor == null)
            	continue;
            CoinThumb thumb = processor.getThumb();
            thumbs.add(thumb);
        }
    	//log.info("thumbs={}", thumbs);
        return thumbs;
    }
    
    @ApiOperation(value="获取当前行情", notes="获取当前行情价格")
    @RequestMapping("symbol-price")
    public Map<String, BigDecimal> findSymbolPrice(){
    	return tradingAccountMonitor.getPriceMapAtPresent();
    }

    /**
     * 查询最近成交记录
     * @param symbol 交易对符号
     * @param size 返回记录最大数量
     * @return
     */
    @RequestMapping("latest-trade")
    public List<ContractTrade> latestTrade(String symbol, int size){
        ContractCoinMatch match = contractCoinMatchFactory.getContractCoinMatch(symbol);
        if (match == null) {
            return null;
        }
        return match.getLastedTradeList();
    }

    /**
     * 获取某交易对详情
     * @param symbol
     * @return
     */
    @RequestMapping("symbol-info")
    public ContractCoin findSymbol(String symbol){
        ContractCoin coin = coinService.findBySymbol(symbol);
        coin.setCurrentTime(Calendar.getInstance().getTimeInMillis());
        ContractCoinVo vo = new ContractCoinVo();
        BeanUtils.copyProperties(coin, vo);
        vo.setDecimalScale(coin.getMinScale());
        return vo;
    }

    @RequestMapping("exchange-plate")
    public Map<String,List<TradePlateItem>> findTradePlate(String symbol){
        log.info("exchange-plate={}", symbol);
    	String serviceName = "market-api";
        String marketUrl = "http://" + serviceName + "/market/exchange-plate?symbol="+symbol;

        ParameterizedTypeReference<Map<String, List<TradePlateItem>>> typeRef = new ParameterizedTypeReference<Map<String, List<TradePlateItem>>>() {};
        ResponseEntity<Map<String, List<TradePlateItem>>> responseEntity = restTemplate.exchange(marketUrl, HttpMethod.POST, new HttpEntity<>(null), typeRef);
        Map<String, List<TradePlateItem>> plates =responseEntity.getBody();
        log.info("plates={}", plates);
        return plates;
    }

    @RequestMapping("exchange-plate-mini")
    public Map<String, JSONObject> findTradePlateMini(String symbol){
    	log.info("exchange-plate-mini={}", symbol);
    	String serviceName = "market-api";
        String marketUrl = "http://" + serviceName + "/market/exchange-plate-mini?symbol="+symbol;

        ParameterizedTypeReference<Map<String, JSONObject>> typeRef = new ParameterizedTypeReference<Map<String, JSONObject>>() {};
        ResponseEntity<Map<String, JSONObject>> responseEntity = restTemplate.exchange(marketUrl, HttpMethod.POST, new HttpEntity<>(null), typeRef);
        Map<String, JSONObject> plates =responseEntity.getBody();
        log.info("plates={}", plates);

        return plates;
    }
    
    @RequestMapping("test")
    public String test(){
    	redisLock.lockBySeconds("test", 20);
    	log.info("return={}", redisLock.waitLockWithSeconds("test", 10, 3));
    	return "";
    	/*logger.info("start rake back...");
        List<Long> memberIdList = new ArrayList<Long>();
        List<Long> followMemberIdList = new ArrayList<Long>();
        
        List<ContractOrderEntrust> list = contractOrderEntrustService.findCanRewardOrders();
        if(list!=null && list.size()>0){
            for(ContractOrderEntrust orderEntrust:list){
            	logger.info("order={}", orderEntrust);
                contractRewardRecordService.sendReturnRewardTemp(orderEntrust, memberIdList, followMemberIdList);
            }
        }
        
        for(Long memberId: memberIdList) {
        	logger.info("trading-account-change memberId={}", memberId);
        	kafkaTemplate.send("trading-account-change", memberId+"");
        }
        for(Long memberId: followMemberIdList) {
        	logger.info("follow-account-change memberId={}", memberId);
        	kafkaTemplate.send("follow-account-change", memberId+"");
        }
        logger.info("end rake back...");
        return "";*/
    }

    @RequestMapping("exchange-plate-full")
    public Map<String,JSONObject> findTradePlateFull(String symbol){
    	log.info("exchange-plate-full={}", symbol);
        Map<String, JSONObject> result = new HashMap<>();
        ContractCoinMatch match = contractCoinMatchFactory.getContractCoinMatch(symbol);
        if (match == null) {
            return null;
        }
        result.put("bid", match.getTradePlate(ContractOrderDirection.BUY).toJSON());
        result.put("ask", match.getTradePlate(ContractOrderDirection.SELL).toJSON());

        return result;
    }
    
    @GetMapping("volume")
    public JSONArray getVolumes() {
    	JSONArray jsonArray = new JSONArray();
    	String[] dates = DateUtil.getTodaySartAndEndDateStr();
    	List<ContractCoinStat> list = coinService.statVolume(dates[0], dates[1]);
    	BigDecimal total = BigDecimal.ZERO;
    	for(ContractCoinStat stat: list) {
    		JSONObject object = new JSONObject();
    		object.put("symbol", stat.getSymbol());
    		BigDecimal volume = stat.getVolume().multiply(BigDecimal.valueOf(2000)).setScale(2, BigDecimal.ROUND_DOWN);
    		object.put("volume", volume);
    		total = total.add(volume);
    		jsonArray.add(object);
    	}
    	JSONObject totalJSONObject = new JSONObject();
    	totalJSONObject.put("symbol", "total");
    	totalJSONObject.put("volume", total);
		jsonArray.add(totalJSONObject);
    	
    	return jsonArray;
    }

    /**
     * 获取币种历史K线
     * @param symbol
     * @param from
     * @param to
     * @param resolution
     * @return
     */
    @RequestMapping("history")
    public JSONArray findKHistory(String symbol, long from, long to, String resolution){
        String period = "";
        log.info("请求参数symbol{},resolution{}",symbol,resolution);
        if(resolution.endsWith("H") || resolution.endsWith("h")){
            period = resolution.substring(0,resolution.length()-1) + "hour";
        }
        else if(resolution.endsWith("D") || resolution.endsWith("d")){
            period = resolution.substring(0,resolution.length()-1) + "day";
        }
        else if(resolution.endsWith("W") || resolution.endsWith("w")){
            period = resolution.substring(0,resolution.length()-1) + "week";
        }
        else if(resolution.endsWith("M") || resolution.endsWith("m")){
            period = resolution.substring(0,resolution.length()-1) + "mon";
        }
        else{
            Integer val = Integer.parseInt(resolution);
            if(val <= 60) {
                period = resolution + "min";
            }
            else {
                period = (val/60) + "hour";
            }
        }
        from = from / 1000;
        to = to / 1000;
        log.info("最终查询条件period{}",period);
        period = toMarketPeriod(period);
        List<KLine> list = marketService.findAllKLine(symbol,from,to,period);
        JSONArray array = new JSONArray();
        for(KLine item:list){
            JSONArray group = new JSONArray();
            group.add(0,item.getTime()* 1000);
            group.add(1,item.getOpenPrice());
            group.add(2,item.getHighestPrice());
            group.add(3,item.getLowestPrice());
            group.add(4,item.getClosePrice());
            group.add(5,item.getVolume());
            array.add(group);
        }
        return array;
    }
    /** doge period → market period（MySQL中存储的格式） */
    static String toMarketPeriod(String dogePeriod) {
        switch (dogePeriod) {
            case "1min":  return "1m";
            case "5min":  return "5m";
            case "15min": return "15m";
            case "30min": return "30m";
            case "60min": return "1h";
            case "4hour": return "4h";
            case "1day":  return "1d";
            case "1week": return "1w";
            case "1mon":  return "1mon";
            default:      return dogePeriod;
        }
    }
}
