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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
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;
import org.springframework.test.util.ReflectionTestUtils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.trading.TradeOrderTestSamples;
import com.ruoyi.web.modules.trading.domain.BizTradeOrder;
import com.ruoyi.web.modules.trading.GradeWeightConfigTestSamples;
import com.ruoyi.web.modules.trading.mapper.BizDistributorMapper;
import com.ruoyi.web.modules.trading.mapper.BizGradeWeightConfigMapper;
import com.ruoyi.web.modules.trading.mapper.BizMarketEntryEarTagMapper;
import com.ruoyi.web.modules.trading.mapper.BizSupplierMapper;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@DisplayName("TradeOrderValidation")
class TradeOrderValidationTest
{
    @Mock
    private BizSupplierMapper bizSupplierMapper;

    @Mock
    private BizDistributorMapper bizDistributorMapper;

    @Mock
    private TradeOrderEarTagResolver tradeOrderEarTagResolver;

    @Mock
    private BizMarketEntryEarTagMapper bizMarketEntryEarTagMapper;

    @Mock
    private BizGradeWeightConfigMapper bizGradeWeightConfigMapper;

    @InjectMocks
    private TradeOrderValidation validation;

    @BeforeEach
    void stubRefs()
    {
        TradeOrderGradeResolver gradeResolver = new TradeOrderGradeResolver();
        ReflectionTestUtils.setField(gradeResolver, "bizGradeWeightConfigMapper", bizGradeWeightConfigMapper);
        ReflectionTestUtils.setField(validation, "tradeOrderGradeResolver", gradeResolver);
        when(bizSupplierMapper.selectBizSupplierById(TradeOrderTestSamples.SUPPLIER_ID_1))
                .thenReturn(TradeOrderTestSamples.supplierPerHead());
        when(bizDistributorMapper.selectBizDistributorById(TradeOrderTestSamples.DISTRIBUTOR_ID_1))
                .thenReturn(TradeOrderTestSamples.activeDistributor());
        when(bizMarketEntryEarTagMapper.selectDistinctEarTagsBySupplierId(TradeOrderTestSamples.SUPPLIER_ID_1))
                .thenReturn(Arrays.asList("E101", "E104"));
        when(tradeOrderEarTagResolver.listEligible(eq(TradeOrderTestSamples.SUPPLIER_ID_1), any()))
                .thenReturn(Arrays.asList("E101", "E104"));
        when(tradeOrderEarTagResolver.loadOccupiedEarTags(any())).thenReturn(Collections.emptySet());
        when(bizGradeWeightConfigMapper.selectAllOrderBySort())
                .thenReturn(GradeWeightConfigTestSamples.standardList());
    }

    @Test
    @DisplayName("ZCZX-JYDDGL-UT-006 合法保存汇总")
    void ut006_validSave()
    {
        BizTradeOrder row = TradeOrderTestSamples.normalSaveRow();
        validation.prepareAndValidateForSave(row);
        assertEquals(1, row.getTotalHeads());
        assertEquals(new BigDecimal("8000.00"), row.getTotalAmount());
        assertEquals("B", row.getLineList().get(0).getGradeCode());
        assertEquals("二级", row.getLineList().get(0).getGradeName());
    }

    @Test
    @DisplayName("ZCZX-JYDDGL-UT-012 两行金额汇总")
    void ut012_twoLinesSum()
    {
        BizTradeOrder row = TradeOrderTestSamples.twoLineSaveRow();
        validation.prepareAndValidateForSave(row);
        assertEquals(2, row.getTotalHeads());
        assertEquals(new BigDecimal("15500.00"), row.getTotalAmount());
        assertEquals("B", row.getLineList().get(0).getGradeCode());
        assertEquals("二级", row.getLineList().get(0).getGradeName());
        assertEquals("C", row.getLineList().get(1).getGradeCode());
        assertEquals("三级", row.getLineList().get(1).getGradeName());
    }

    @Test
    @DisplayName("ZCZX-JYDDGL-UT-006 缺明细")
    void ut006_noLine()
    {
        BizTradeOrder row = TradeOrderTestSamples.normalSaveRow();
        row.setLineList(Collections.emptyList());
        assertThrows(ServiceException.class, () -> validation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("ZCZX-JYDDGL-UT-011 重量金额非法")
    void ut011_invalidAmount()
    {
        BizTradeOrder row = TradeOrderTestSamples.normalSaveRow();
        row.getLineList().get(0).setWeight(BigDecimal.ZERO);
        assertThrows(ServiceException.class, () -> validation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("ZCZX-JYDDGL-UT-009 耳标不在池")
    void ut009_earTagInvalid()
    {
        when(tradeOrderEarTagResolver.listEligible(any(), any()))
                .thenReturn(Collections.singletonList("E101"));
        BizTradeOrder row = TradeOrderTestSamples.normalSaveRow();
        row.getLineList().get(0).setEarTag("E999");
        assertThrows(ServiceException.class, () -> validation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("ZCZX-JYDDGL-UT-013 已完成不可改")
    void ut013_completed()
    {
        BizTradeOrder existing = TradeOrderTestSamples.pendingRow();
        existing.setOrderStatus(TradeOrderRules.ORDER_STATUS_COMPLETED);
        assertThrows(ServiceException.class, () -> validation.assertPendingForUpdate(existing));
    }

    @Test
    @DisplayName("ZCZX-JYDDGL-UT-023 收费未配置")
    void ut023_noFee()
    {
        when(bizSupplierMapper.selectBizSupplierById(1L)).thenReturn(TradeOrderTestSamples.supplierNoFee());
        assertThrows(ServiceException.class,
                () -> validation.assertSupplierFeeConfigured(TradeOrderTestSamples.SUPPLIER_ID_1));
    }
}
