package com.lanyuanxiaoyao.leopard.core.service;

import cn.hutool.core.util.ObjectUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.core.entity.QDaily;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 计算行业相关指标
 *
 * @author lanyuanxiaoyao
 * @version 20250924
 */
@Slf4j
@Service
public class IndustryService {
  private final StockRepository stockRepository;
  private final DailyRepository dailyRepository;

  public IndustryService(StockRepository stockRepository, DailyRepository dailyRepository) {
    this.stockRepository = stockRepository;
    this.dailyRepository = dailyRepository;
  }

  public Map<IndustryYearlyKey, Double> topChange(int year) {
    return topChange(year, null);
  }

  public Map<IndustryYearlyKey, Double> topChange(int year, Set<Stock> includeStocks) {
    return topChange(year, year, includeStocks);
  }

  public Map<IndustryYearlyKey, Double> topChange(int startYear, int endYear) {
    return topChange(startYear, endYear, null);
  }

  public Map<IndustryYearlyKey, Double> topChange(int startYear, int endYear, Set<Stock> includeStocks) {
    var includeIndustries = ObjectUtil.isNull(includeStocks)
      ? null
      : includeStocks.stream().map(Stock::getIndustry).collect(Collectors.toSet());
    return stockRepository.findDistinctIndustries()
      .parallelStream()
      .filter(o -> ObjectUtil.isNull(includeIndustries) || includeIndustries.contains(o))
      .flatMap(industry -> {
        var keys = new ArrayList<IndustryYearlyKey>();
        for (int year = startYear; year <= endYear; year++) {
          keys.add(new IndustryYearlyKey(industry, year));
        }
        return keys.stream();
      })
      .map(key -> {
        var maxChange = dailyRepository
          .findAll(
            QDaily.daily.stock.industry.eq(key.industry())
              .and(QDaily.daily.stock.in(includeStocks))
              .and(QDaily.daily.tradeDate.year().eq(key.year())),
            QDaily.daily.tradeDate.asc()
          )
          .stream()
          .collect(Collectors.groupingBy(Daily::getStock))
          .values()
          .stream()
          .mapToDouble(dailies -> {
            var dailiesSorted = dailies
              .stream()
              .sorted(Comparator.comparing(Daily::getTradeDate))
              .toList();
            return (dailiesSorted.getLast().getHfqClose() - dailiesSorted.getFirst().getHfqClose()) / dailiesSorted.getFirst().getHfqClose();
          })
          .max()
          .orElse(0.0);
        return Map.entry(key, maxChange);
      })
      .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
  }

  public record IndustryYearlyKey(String industry, int year) {
  }

  public record IndustryYearlyData(
    String industry,
    int year,
    double maxChange,
    double minChange,
    double avgChange,
    double medianChange
  ) {
  }
}
