package com.ruoyi.web.modules.technology.service.impl;

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.argThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Date;
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 com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.technology.PracticalTrainingTestSamples;
import com.ruoyi.web.modules.technology.domain.BizPracticalTraining;
import com.ruoyi.web.modules.technology.mapper.BizPracticalTrainingMapper;
import com.ruoyi.web.modules.technology.support.PracticalTrainingRules;
import com.ruoyi.web.modules.technology.support.PracticalTrainingStatusSupport;

@ExtendWith(MockitoExtension.class)
@DisplayName("BizPracticalTrainingServiceImpl")
class BizPracticalTrainingServiceImplTest
{

    @Mock
    private BizPracticalTrainingMapper mapper;

    @Mock
    private PracticalTrainingStatusSupport practicalTrainingStatusSupport;

    @InjectMocks
    private BizPracticalTrainingServiceImpl service;

    @Test
    @DisplayName("新增仅保存未发布")
    void insertDraft()
    {
        when(mapper.insertBizPracticalTraining(any())).thenReturn(1);
        assertEquals(1, service.insertBizPracticalTraining(PracticalTrainingTestSamples.sampleDraft()));
        verify(mapper).insertBizPracticalTraining(argThat(r ->
                r.getPublishStatus() == PracticalTrainingRules.PUBLISH_STATUS_DRAFT
                        && r.getPublishTime() == null
                        && PracticalTrainingRules.DEL_FLAG_NORMAL.equals(r.getDelFlag())));
        verify(mapper, never()).updateBizPracticalTraining(any());
    }

    @Test
    @DisplayName("新增 saveAndPublish")
    void insertSaveAndPublish()
    {
        when(mapper.insertBizPracticalTraining(any())).thenAnswer(inv -> {
            BizPracticalTraining r = inv.getArgument(0);
            r.setId(10L);
            return 1;
        });
        when(mapper.selectBizPracticalTrainingById(10L)).thenAnswer(inv -> {
            BizPracticalTraining r = PracticalTrainingTestSamples.sampleDraft();
            r.setId(10L);
            return r;
        });
        when(mapper.updateBizPracticalTraining(any())).thenReturn(1);
        BizPracticalTraining row = PracticalTrainingTestSamples.sampleDraft();
        row.setSaveAndPublish(true);
        assertEquals(1, service.insertBizPracticalTraining(row));
        verify(mapper).updateBizPracticalTraining(argThat(r -> r.getPublishStatus() == 1));
    }

    @Test
    @DisplayName("修改未发布记录回填 training_status")
    void updateDraftSetsTrainingStatus()
    {
        BizPracticalTraining db = PracticalTrainingTestSamples.sampleDraft();
        db.setId(2L);
        db.setTrainingStatus(PracticalTrainingRules.TRAINING_STATUS_NOT_STARTED);
        when(mapper.selectBizPracticalTrainingById(2L)).thenReturn(db);
        when(mapper.updateBizPracticalTraining(any())).thenReturn(1);
        BizPracticalTraining in = PracticalTrainingTestSamples.sampleDraft();
        in.setId(2L);
        in.setTrainingLocation("新地点");
        in.setTrainingStatus(null);
        assertEquals(1, service.updateBizPracticalTraining(in));
        verify(mapper).updateBizPracticalTraining(argThat(r ->
                PracticalTrainingRules.TRAINING_STATUS_NOT_STARTED.equals(r.getTrainingStatus())));
    }

    @Test
    @DisplayName("已发布禁止修改")
    void updatePublished()
    {
        BizPracticalTraining db = PracticalTrainingTestSamples.sampleDraft();
        db.setId(1L);
        db.setPublishStatus(PracticalTrainingRules.PUBLISH_STATUS_PUBLISHED);
        when(mapper.selectBizPracticalTrainingById(1L)).thenReturn(db);
        BizPracticalTraining in = PracticalTrainingTestSamples.sampleDraft();
        in.setId(1L);
        in.setTrainingLocation("新地点");
        assertThrows(ServiceException.class, () -> service.updateBizPracticalTraining(in));
        verify(mapper, never()).updateBizPracticalTraining(any());
    }

    @Test
    @DisplayName("发布写状态与时间")
    void publish()
    {
        BizPracticalTraining db = PracticalTrainingTestSamples.sampleDraft();
        db.setId(4L);
        when(mapper.selectBizPracticalTrainingById(4L)).thenReturn(db);
        when(mapper.updateBizPracticalTraining(any())).thenReturn(1);
        assertEquals(1, service.publish(4L));
        verify(mapper).updateBizPracticalTraining(argThat(r ->
                r.getPublishStatus() == 1
                        && r.getPublishTime() != null
                        && r.getTrainingStatus() != null));
    }

    @Test
    @DisplayName("下架保留发布日期")
    void offlineKeepsPublishTime()
    {
        BizPracticalTraining db = PracticalTrainingTestSamples.samplePublishedFutureReg();
        db.setId(5L);
        Date publishTime = new Date();
        db.setPublishTime(publishTime);
        when(mapper.selectBizPracticalTrainingById(5L)).thenReturn(db);
        when(mapper.updateBizPracticalTraining(any())).thenReturn(1);
        assertEquals(1, service.offline(5L));
        verify(mapper).updateBizPracticalTraining(argThat(r ->
                r.getPublishStatus() == 0
                        && r.getPublishTime() == publishTime
                        && r.getOfflineTime() != null));
    }

    @Test
    @DisplayName("有报名记录禁止删除")
    void deleteWithEnrollment()
    {
        BizPracticalTraining db = PracticalTrainingTestSamples.sampleDraft();
        db.setId(6L);
        db.setActualEnrolledCount(3);
        when(mapper.selectBizPracticalTrainingByIdAny(6L)).thenReturn(db);
        assertThrows(ServiceException.class,
                () -> service.deleteBizPracticalTrainingByIds(new Long[] { 6L }, "tester"));
        verify(mapper, never()).logicDeleteBizPracticalTrainingByIds(any(), any());
    }
}
