package com.lanyuanxiaoyao.leopard.core.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Service;

/**
 * 对接TuShare接口
 *
 * @author lanyuanxiaoyao
 * @version 20250828
 */
@Slf4j
@Service
public class TuShareService {
  public static final DateTimeFormatter TRADE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
  private static final String API_URL = "https://api.tushare.pro";
  private static final String API_TOKEN = "64ebff4fa679167600b905ee45dd88e76f3963c0ff39157f3f085f0e";
  private final ObjectMapper mapper;

  public TuShareService(Jackson2ObjectMapperBuilder builder) {
    this.mapper = builder.build();
  }

  @SneakyThrows
  private String buildRequest(String apiName, Map<String, Object> params, List<String> fields) {
    return mapper.writeValueAsString(Map.of(
      "api_name", apiName,
      "token", API_TOKEN,
      "params", params,
      "fields", fields
    ));
  }

  @SneakyThrows
  public TuShareResponse stockList() {
    var response = HttpUtil.post(API_URL, buildRequest(
      "stock_basic",
      Map.of("list_status", "L", "market", "主板", "exchange", "SSE,SZSE"),
      List.of("ts_code", "name", "fullname", "exchange", "industry", "list_date")
    ));
    var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
    if (tuShareResponse.code != 0) {
      throw new RuntimeException(tuShareResponse.message);
    }
    return tuShareResponse;
  }

  public TuShareResponse dailyList(LocalDate tradeDate) {
    return dailyList(tradeDate, null);
  }

  @SneakyThrows
  public TuShareResponse dailyList(LocalDate tradeDate, String stockCode) {
    var paramsMap = new HashMap<String, Object>();
    paramsMap.put("trade_date", tradeDate.format(TRADE_FORMAT));
    if (StrUtil.isNotBlank(stockCode)) {
      paramsMap.put("ts_code", stockCode);
    }
    var response = HttpUtil.post(API_URL, buildRequest(
      "daily",
      paramsMap,
      List.of("ts_code", "trade_date", "open", "high", "low", "close", "pre_close", "change", "pct_chg", "vol", "amount")
    ));
    var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
    if (tuShareResponse.code != 0) {
      throw new RuntimeException(tuShareResponse.message);
    }
    return tuShareResponse;
  }

  @SneakyThrows
  public TuShareResponse tradeDateList(String exchange) {
    var response = HttpUtil.post(API_URL, buildRequest(
      "trade_cal",
      Map.of("exchange", exchange, "is_open", 1),
      List.of("cal_date")
    ));
    var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
    if (tuShareResponse.code != 0) {
      throw new RuntimeException(tuShareResponse.message);
    }
    return tuShareResponse;
  }

  @SneakyThrows
  public TuShareResponse factorList(LocalDate tradeDate) {
    return factorList(tradeDate, null);
  }

  @SneakyThrows
  public TuShareResponse factorList(LocalDate tradeDate, String stockCode) {
    var paramsMap = new HashMap<String, Object>();
    paramsMap.put("trade_date", tradeDate.format(TRADE_FORMAT));
    if (StrUtil.isNotBlank(stockCode)) {
      paramsMap.put("ts_code", stockCode);
    }
    var response = HttpUtil.post(API_URL, buildRequest(
      "adj_factor",
      paramsMap,
      List.of("ts_code", "trade_date", "adj_factor")
    ));
    var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
    if (tuShareResponse.code != 0) {
      throw new RuntimeException(tuShareResponse.message);
    }
    return tuShareResponse;
  }

  public List<Map<String, String>> request(String api, Map<String, Object> params, List<String> fields) throws JsonProcessingException {
    var response = HttpUtil.post(API_URL, buildRequest(api, params, fields));
    var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
    if (tuShareResponse.code != 0) {
      throw new RuntimeException(tuShareResponse.message);
    }
    var data = tuShareResponse.data;
    var result = new ArrayList<Map<String, String>>();
    for (var item : data.items) {
      var map = new HashMap<String, String>();
      for (int i = 0; i < data.fields.size(); i++) {
        map.put(data.fields.get(i), item.get(i));
      }
      result.add(map);
    }
    return result;
  }

  public record TuShareResponse(
    Integer code,
    @JsonProperty("msg")
    String message,
    Data data
  ) {
    public record Data(
      List<String> fields,
      List<List<String>> items
    ) {
    }
  }
}
