package com.lanyuanxiaoyao.leopard.core.task;

import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.core.entity.QDaily;
import com.lanyuanxiaoyao.leopard.core.entity.QYearly;
import com.lanyuanxiaoyao.leopard.core.entity.Yearly;
import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
import com.lanyuanxiaoyao.leopard.core.repository.YearlyRepository;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 更新年线指标
 *
 * @author lanyuanxiaoyao
 * @version 20250924
 */
@Slf4j
@Component
public class UpdateYearlyTask extends TaskRunner {
  private final StockRepository stockRepository;
  private final DailyRepository dailyRepository;
  private final YearlyRepository yearlyRepository;

  protected UpdateYearlyTask(ApplicationContext context, StockRepository stockRepository, DailyRepository dailyRepository, YearlyRepository yearlyRepository) {
    super(context);
    this.stockRepository = stockRepository;
    this.dailyRepository = dailyRepository;
    this.yearlyRepository = yearlyRepository;
  }

  @Transactional(rollbackFor = Throwable.class)
  @Override
  public String process(Map<String, Object> params, StepUpdater updater) {
    var startYear = dailyRepository.findMinTradeDate().getYear();
    var endYear = dailyRepository.findMaxTradeDate().getYear();
    var stocks = stockRepository.findAll();
    for (int year = startYear, index = 0; year <= endYear; year++, index++) {
      for (var stock : stocks) {
        log.info("Processing {} {}", stock.getCode(), year);
        if (stock.getListedDate().getYear() > year) {
          continue;
        }
        var dailies = dailyRepository.findAll(
          QDaily.daily.tradeDate.year().eq(year)
            .and(QDaily.daily.stock.eq(stock))
        );
        var yearly = yearlyRepository.findOne(
          QYearly.yearly.stock.eq(stock)
            .and(QYearly.yearly.year.eq(year))
        ).orElseGet(Yearly::new);
        yearly.setStock(stock);
        yearly.setYear(year);
        yearly.setClose(dailies.getLast().getHfqClose());
        yearly.setOpen(dailies.getFirst().getHfqOpen());
        yearly.setHigh(dailies.stream().map(Daily::getHfqHigh).max(Double::compareTo).orElse(0.0));
        yearly.setLow(dailies.stream().map(Daily::getHfqLow).min(Double::compareTo).orElse(0.0));
        yearly.setVolume(dailies.stream().mapToDouble(Daily::getVolume).sum());
        yearly.setTurnover(dailies.stream().mapToDouble(Daily::getTurnover).sum());
        yearly.setPriceChangeAmount(yearly.getClose() - yearly.getOpen());
        yearly.setPriceFluctuationRange((yearly.getClose() - yearly.getOpen()) / yearly.getOpen());
        yearlyRepository.save(yearly);
      }
      updater.update((year - startYear) * 1.0 / (endYear - startYear + 1));
    }
    return null;
  }
}
