package com.market.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.market.entity.MessageResult;
import com.market.utils.KlineUtils;
import com.market.utils.RequestUtils;
import com.market.websocket.SubscriptionManager;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 24 小时涨跌幅排行接口
 */
@RestController
@RequestMapping("/rank")
@RequiredArgsConstructor
public class MarketRankController {

    private static final String TICKET_PREFIX = KlineUtils.TOPIC_PREFIX;
    private static final String TICKET_SUFFIX = "." + KlineUtils.TOPIC_TICKET;
    private static final int TOP_N = 5;

    private final SubscriptionManager subscriptionManager;
    private final KlineUtils klineUtils;

    /**
     * 测试
     *
     */
    @GetMapping("/test")
    public MessageResult test(HttpServletRequest request) {
        String lang = RequestUtils.getLangFromHeader(request);
        return MessageResult.successLang(lang);
    }

    @GetMapping("/rise")
    public MessageResult rise(HttpServletRequest request) {
        String lang = RequestUtils.getLangFromHeader(request);
        return MessageResult.successLang(lang, rank(false));
    }

    /**
     * 24 小时跌幅前五
     * GET /rank/fall
     */
    @GetMapping("/fall")
    public MessageResult fall(HttpServletRequest request) {
        String lang = RequestUtils.getLangFromHeader(request);
        return MessageResult.successLang(lang, rank(true));
    }

    /**
     * @param ascending true = 跌幅（涨幅从小到大）；false = 涨幅（涨幅从大到小）
     */
    private List<Map<String, Object>> rank(boolean ascending) {
        Map<String, Object> all = subscriptionManager.getLatestsByPrefix(TICKET_PREFIX);

        Comparator<Map<String, Object>> cmp = Comparator.comparing(m -> (BigDecimal) m.get("changePercent"));
        if (!ascending) cmp = cmp.reversed();

        return all.entrySet().stream()
                .filter(e -> e.getKey().endsWith(TICKET_SUFFIX) && e.getValue() instanceof JsonNode)
                .map(e -> buildItem(e.getKey(), (JsonNode) e.getValue()))
                .filter(Objects::nonNull)
                .sorted(cmp)
                .limit(TOP_N)
                .collect(Collectors.toList());
    }

    private Map<String, Object> buildItem(String topic, JsonNode data) {
        try {
            // topic = market.{symbol}.ticket
            String symbol = topic.split("\\.")[1];
            BigDecimal close = new BigDecimal(data.get("c").asText());
            BigDecimal open  = new BigDecimal(data.get("o").asText());
            if (open.compareTo(BigDecimal.ZERO) == 0) return null;

            BigDecimal changePercent = close.subtract(open)
                    .divide(open, 8, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100))
                    .setScale(4, RoundingMode.HALF_UP);

            Map<String, Object> item = new LinkedHashMap<>();
            item.put("symbol", symbol.toUpperCase());
            item.put("closePrice", close.toPlainString());
            item.put("openPrice", open.toPlainString());
            item.put("highPrice", data.get("h").asText());
            item.put("lowPrice", data.get("l").asText());
            item.put("volume", data.get("v").asText());
            item.put("changePercent", changePercent);
            return item;
        } catch (Exception e) {
            return null;
        }
    }
}
