package com.ruoyi.web.modules.trading.support;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.when;

import java.math.BigDecimal;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.circulation.domain.BizTradeMarket;
import com.ruoyi.web.modules.circulation.mapper.BizTradeMarketMapper;
import com.ruoyi.web.modules.circulation.support.TradeMarketRules;
import com.ruoyi.web.modules.trading.MarketDailyQuoteTestSamples;
import com.ruoyi.web.modules.trading.domain.BizMarketDailyQuote;
import com.ruoyi.web.modules.trading.mapper.BizMarketDailyQuoteMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@DisplayName("MarketDailyQuoteValidation")
class MarketDailyQuoteValidationTest
{
    @Mock
    private BizTradeMarketMapper bizTradeMarketMapper;

    @Mock
    private BizMarketDailyQuoteMapper bizMarketDailyQuoteMapper;

    @InjectMocks
    private MarketDailyQuoteValidation validation;

    @BeforeEach
    void stub()
    {
        when(bizTradeMarketMapper.selectBizTradeMarketById(MarketDailyQuoteTestSamples.TRADE_MARKET_ID))
                .thenReturn(MarketDailyQuoteTestSamples.activeTradeMarket());
        when(bizMarketDailyQuoteMapper.countDuplicateDimension(any(), any(), any(), any(),
                anyInt(), anyInt(), anyInt(), anyInt(), isNull())).thenReturn(0);
    }

    @Test
    @DisplayName("合法全量")
    void valid() throws ParseException
    {
        assertDoesNotThrow(() -> validation.prepareAndValidateForSave(
                MarketDailyQuoteTestSamples.validSaveRow(), null));
    }

    @Test
    @DisplayName("概率合计100")
    void probSum()
    {
        assertDoesNotThrow(() -> MarketDailyQuoteValidation.validateProbabilities(
                new BigDecimal("40"), new BigDecimal("35"), new BigDecimal("25")));
        assertThrows(ServiceException.class, () -> MarketDailyQuoteValidation.validateProbabilities(
                new BigDecimal("50"), new BigDecimal("30"), new BigDecimal("30")));
    }

    @Test
    @DisplayName("未来行情日期")
    void futureDate() throws ParseException
    {
        BizMarketDailyQuote row = MarketDailyQuoteTestSamples.validSaveRow();
        LocalDate tomorrow = LocalDate.now().plusDays(1);
        row.setQuoteDate(Date.from(tomorrow.atStartOfDay(ZoneId.systemDefault()).toInstant()));
        assertThrows(ServiceException.class, () -> validation.prepareAndValidateForSave(row, null));
    }

    @Test
    @DisplayName("市场停业")
    void marketSuspended()
    {
        BizTradeMarket m = MarketDailyQuoteTestSamples.activeTradeMarket();
        m.setOperateStatus(TradeMarketRules.OPERATE_STATUS_SUSPENDED);
        when(bizTradeMarketMapper.selectBizTradeMarketById(any())).thenReturn(m);
        assertThrows(ServiceException.class, () -> {
            try
            {
                validation.prepareAndValidateForSave(MarketDailyQuoteTestSamples.validSaveRow(), null);
            }
            catch (ParseException ex)
            {
                throw new RuntimeException(ex);
            }
        });
    }

    @Test
    @DisplayName("维度重复")
    void duplicate()
    {
        when(bizMarketDailyQuoteMapper.countDuplicateDimension(any(), any(), any(), any(),
                anyInt(), anyInt(), anyInt(), anyInt(), eq(null))).thenReturn(1);
        assertThrows(ServiceException.class, () -> {
            try
            {
                validation.prepareAndValidateForSave(MarketDailyQuoteTestSamples.validSaveRow(), null);
            }
            catch (ParseException ex)
            {
                throw new RuntimeException(ex);
            }
        });
    }
}
