package link.at17.mid.tushare.dao;

import com.alibaba.fastjson2.JSONObject;
import com.github.yulichang.base.MPJBaseMapper;

import link.at17.mid.tushare.annotation.BatchInsert;
import link.at17.mid.tushare.annotation.BatchList;
import link.at17.mid.tushare.data.models.StockCalendar;
import link.at17.mid.tushare.enums.StockMarket;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.temporal.Temporal;
import java.util.List;


@Component
@Mapper
public interface StockCalendarDao extends MPJBaseMapper<StockCalendar> {
    /**
     * 更新股票日历
     * @param list
     */
    @BatchInsert
    int insertOrUpdateList(@BatchList List<JSONObject> list);

    /**
     * 获取数据库内指定证交所的最近一个交易日历
     * @param stockMarket 指定证交所，若为 {@code null} 则取最近一条（市场不确定）
     * @return
     */
    StockCalendar getLatest(@Nullable StockMarket stockMarket);
    
    /**
     * 获取数据库内指定证交所的最早一个交易日历
     * <p>仅为日期，并未指定是否是开市日
     * @param stockMarket 指定证交所，若为 {@code null} 则取最早一条（市场不确定）
     * @return
     */
    StockCalendar getGreatest(@Nullable StockMarket stockMarket);
    
    
    /**
     * 获取指定证交所两个日期（含）之间的交易日个数<br>
     * <p>
     * 存储在数据库内的类型为无时分秒的 timestamp 类型，可视作 {@code java.time.LocalDate} <br>
     * 若传入的是 java.time.LocalDateTime 类型，会忽略时分秒
     * <p>例：
     * <ul><li>
     * <code>startDate&nbsp;: LocalDateTime 2021-08-16 01:20:30</code><br>
     * <code>endDate&nbsp;&nbsp;&nbsp;: LocalDateTime 2021-08-20 19:20:30</code><br>
     * 返回 5
     * <li><code>countOpenDaysBetween(StockMarket.<b><i>SH</i></b>, startDate, endDate)</code> 其中<br>
     * <code>startDate&nbsp;: LocalDateTime 2021-08-16 01:20:30</code><br>
     * <code>endDate&nbsp;&nbsp;&nbsp;: LocalDateTime 2021-08-16 12:34:56</code><br>
     * 返回 1
     * <li><code>countOpenDaysBetween(StockMarket.<b><i>SH</i></b>, startDate, endDate)</code> 其中<br>
     * <code>startDate&nbsp;: LocalDateTime 2021-08-15 01:20:30</code><br>
     * <code>endDate&nbsp;&nbsp;&nbsp;: LocalDateTime 2021-08-16 12:34:56</code><br>
     * 返回 1
     * </ul>
     * </p>
     * @param exchange 股市类型枚举，若提供的枚举不为 SZ 或 SH，则采用 SZ + SH 的所有交易日并去重计算
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return
     
    */
    long countOpenDaysBetween(@Param("exchange") StockMarket exchange, @Param("startDate") Temporal startDate, @Param("endDate") Temporal endDate);
    
    

    /**
     * 获取指定证交所两个日期（含）之间的所有交易日<br>
     * 存储在数据库内的类型为无时分秒的 timestamp 类型，可视作 {@code java.time.LocalDate} <br>
     * 若传入的是 java.time.LocalDateTime 类型，会忽略时分秒
     * <p>例：
     * <ul><li><code>countOpenDaysBetween(StockMarket.<b><i>SH</i></b>, startDate, endDate)</code> 其中<br>
     * <code>startDate&nbsp;: LocalDateTime 2021-08-16 01:20:30</code><br>
     * <code>endDate&nbsp;&nbsp;: LocalDateTime 2021-08-20 19:20:30</code><br>
     * </p>
     * <p>
     * 返回：
     * <ul>
     * <li>2021-08-16
     * <li>2021-08-17
     * <li>2021-08-18
     * <li>2021-08-19
     * <li>2021-08-20
     * </ul>
     * </p>
     * @param exchange 股市类型枚举，若提供的枚举不为 SZ 或 SH，则采用 SZ + SH 的所有交易日并去重获得结果
     * @param startDate 开始日期(含)
     * @param endDate 结束日期(含)
     * @return
     
    */
    List<LocalDateTime> getAllOpenDatesBetween(@Param("exchange") StockMarket exchange, @Param("startDate") Temporal startDate, @Param("endDate") Temporal endDate);
    
    /**
     * 获取指定证交所指定日期偏移的指定交易日
     * @param exchange
     * @param date
     * @param offset
     * @return
     */
    LocalDateTime getOpenDateOffset(@Param("exchange") StockMarket exchange, @Param("date") Temporal date, @Param("offset") long offset);
    
    /**
     * 获取指定证交所指定日期（含）以后的所有交易日
     * @param exchange
     * @param sence 留空则查询所有
     * @return
     */
    List<LocalDateTime> getAllOpenDateSence(@Param("exchange") @Nullable StockMarket exchange, @Param("after") @Nullable Temporal sence);
    
    /**
     * 判断指定日是否为指定交易所的交易日
     * @param date 会截断时分秒，只取年月日
     * @param exchange 目前只支持 SSE（深交所）和 SHSE（上交所）
     * @return
     * @see StockCalendarDao#isOpen(Temporal, StockMarket)
     */
    boolean isOpen(@Param("date") @NonNull Temporal date, @Param("exchange") @Nullable StockMarket exchange);

}
