package com.ruoyi.web.modules.farming.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.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

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.kb.support.KbApiProperties;
import com.ruoyi.web.kb.service.KnowledgeBaseClient;
import com.ruoyi.web.modules.farming.LivestockKnowledgeTestSamples;
import com.ruoyi.web.modules.farming.domain.BizLivestockKnowledge;
import com.ruoyi.web.modules.farming.mapper.BizLivestockKnowledgeMapper;
import com.ruoyi.web.modules.farming.support.LivestockKnowledgeRules;

@ExtendWith(MockitoExtension.class)
@DisplayName("BizLivestockKnowledgeServiceImpl")
class BizLivestockKnowledgeServiceImplTest
{

    @Mock
    private BizLivestockKnowledgeMapper mapper;

    @Mock
    private KnowledgeBaseClient knowledgeBaseClient;

    @Mock
    private KbApiProperties kbApiProperties;

    @InjectMocks
    private BizLivestockKnowledgeServiceImpl service;

    @Test
    @DisplayName("新增落库未入库")
    void insert()
    {
        when(mapper.insertBizLivestockKnowledge(any())).thenReturn(1);
        assertEquals(1, service.insertBizLivestockKnowledge(LivestockKnowledgeTestSamples.sampleDraft()));
        verify(mapper).insertBizLivestockKnowledge(argThat(r ->
                r.getKbSyncStatus() == LivestockKnowledgeRules.KB_SYNC_NOT_IN
                        && r.getKbDocId() == null
                        && LivestockKnowledgeRules.DEL_FLAG_NORMAL.equals(r.getDelFlag())));
    }

    @Test
    @DisplayName("已入库禁止修改")
    void updateSyncedThrows()
    {
        BizLivestockKnowledge db = LivestockKnowledgeTestSamples.sampleSynced();
        when(mapper.selectBizLivestockKnowledgeById(3L)).thenReturn(db);
        BizLivestockKnowledge in = LivestockKnowledgeTestSamples.sampleDraft();
        in.setId(3L);
        in.setKnowledgeTitle("新标题");
        assertThrows(ServiceException.class, () -> service.updateBizLivestockKnowledge(in));
        verify(mapper, never()).updateBizLivestockKnowledge(any());
    }

    @Test
    @DisplayName("未入库修改不调知识库")
    void updateUnsynced()
    {
        BizLivestockKnowledge db = LivestockKnowledgeTestSamples.sampleDraft();
        db.setId(1L);
        when(mapper.selectBizLivestockKnowledgeById(1L)).thenReturn(db);
        when(mapper.updateBizLivestockKnowledge(any())).thenReturn(1);
        BizLivestockKnowledge in = LivestockKnowledgeTestSamples.sampleDraft();
        in.setId(1L);
        in.setIntroduction("新简介");
        assertEquals(1, service.updateBizLivestockKnowledge(in));
        verify(knowledgeBaseClient, never()).uploadFileByUrl(any(), any(), any());
    }

    @Test
    @DisplayName("同步成功")
    void syncKb()
    {
        BizLivestockKnowledge db = LivestockKnowledgeTestSamples.sampleDraft();
        db.setId(2L);
        when(mapper.selectBizLivestockKnowledgeById(2L)).thenReturn(db);
        when(kbApiProperties.getFileUrlBase()).thenReturn(null);
        when(knowledgeBaseClient.uploadFileByUrl(any(), eq("综合牧业知识"), eq("春季饲喂要点")))
                .thenReturn("DOC-2");
        when(mapper.updateBizLivestockKnowledge(any())).thenReturn(1);
        assertEquals(1, service.syncKb(2L));
        verify(mapper).updateBizLivestockKnowledge(argThat(r ->
                r.getKbSyncStatus() == LivestockKnowledgeRules.KB_SYNC_IN
                        && "DOC-2".equals(r.getKbDocId())));
    }

    @Test
    @DisplayName("重复同步拒绝")
    void syncKbAlreadyIn()
    {
        when(mapper.selectBizLivestockKnowledgeById(3L))
                .thenReturn(LivestockKnowledgeTestSamples.sampleSynced());
        assertThrows(ServiceException.class, () -> service.syncKb(3L));
    }

    @Test
    @DisplayName("同步失败不改状态")
    void syncKbFails()
    {
        BizLivestockKnowledge db = LivestockKnowledgeTestSamples.sampleDraft();
        db.setId(4L);
        when(mapper.selectBizLivestockKnowledgeById(4L)).thenReturn(db);
        when(kbApiProperties.getFileUrlBase()).thenReturn(null);
        when(knowledgeBaseClient.uploadFileByUrl(any(), any(), any()))
                .thenThrow(new RuntimeException("timeout"));
        assertThrows(ServiceException.class, () -> service.syncKb(4L));
        verify(mapper, never()).updateBizLivestockKnowledge(any());
    }

    @Test
    @DisplayName("移出成功")
    void removeKb()
    {
        BizLivestockKnowledge db = LivestockKnowledgeTestSamples.sampleSynced();
        when(mapper.selectBizLivestockKnowledgeById(3L)).thenReturn(db);
        when(mapper.updateBizLivestockKnowledge(any())).thenReturn(1);
        assertEquals(1, service.removeKb(3L));
        verify(knowledgeBaseClient).deleteFile("DOC-3");
        verify(mapper).updateBizLivestockKnowledge(argThat(r ->
                r.getKbSyncStatus() == LivestockKnowledgeRules.KB_SYNC_NOT_IN && r.getKbDocId() == null));
    }

    @Test
    @DisplayName("未入库移出拒绝")
    void removeKbNotIn()
    {
        BizLivestockKnowledge db = LivestockKnowledgeTestSamples.sampleDraft();
        db.setId(1L);
        when(mapper.selectBizLivestockKnowledgeById(1L)).thenReturn(db);
        assertThrows(ServiceException.class, () -> service.removeKb(1L));
    }

    @Test
    @DisplayName("已入库禁止删除")
    void deleteSyncedThrows()
    {
        when(mapper.selectBizLivestockKnowledgeById(3L))
                .thenReturn(LivestockKnowledgeTestSamples.sampleSynced());
        assertThrows(ServiceException.class,
                () -> service.deleteBizLivestockKnowledgeByIds(new Long[] { 3L }, "tester"));
        verify(mapper, never()).logicDeleteBizLivestockKnowledgeByIds(any(), any());
    }

    @Test
    @DisplayName("未入库逻辑删除")
    void deleteUnsynced()
    {
        BizLivestockKnowledge db = LivestockKnowledgeTestSamples.sampleDraft();
        db.setId(5L);
        when(mapper.selectBizLivestockKnowledgeById(5L)).thenReturn(db);
        when(mapper.logicDeleteBizLivestockKnowledgeByIds(any(), eq("tester"))).thenReturn(1);
        assertEquals(1, service.deleteBizLivestockKnowledgeByIds(new Long[] { 5L }, "tester"));
        verify(mapper).logicDeleteBizLivestockKnowledgeByIds(new Long[] { 5L }, "tester");
    }
}
