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

import java.io.File;
import java.nio.file.Paths;
import java.util.Collections;

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.support.KbMarkdownGenerator;
import com.ruoyi.web.kb.service.KnowledgeBaseClient;
import com.ruoyi.web.modules.architecture.domain.BizDrugIncompatibilityCompanion;
import com.ruoyi.web.modules.architecture.domain.BizDrugIncompatibilityStandard;
import com.ruoyi.web.modules.architecture.mapper.BizDrugIncompatibilityCompanionMapper;
import com.ruoyi.web.modules.architecture.mapper.BizDrugIncompatibilityStandardMapper;
import com.ruoyi.web.modules.architecture.support.DrugIncompatibilityStandardKbMarkdown;

@ExtendWith(MockitoExtension.class)
@DisplayName("BizDrugIncompatibilityStandardServiceImpl")
class BizDrugIncompatibilityStandardServiceImplTest
{

    @Mock
    private BizDrugIncompatibilityStandardMapper standardMapper;

    @Mock
    private BizDrugIncompatibilityCompanionMapper companionMapper;

    @Mock
    private KnowledgeBaseClient knowledgeBaseClient;

    @Mock
    private KbApiProperties kbApiProperties;

    @Mock
    private DrugIncompatibilityStandardKbMarkdown drugIncompatibilityKbMarkdown;

    @Mock
    private KbMarkdownGenerator kbMarkdownGenerator;

    @InjectMocks
    private BizDrugIncompatibilityStandardServiceImpl service;

    @Test
    @DisplayName("新增写子表")
    void insert()
    {
        when(standardMapper.insertBizDrugIncompatibilityStandard(any())).thenAnswer(inv -> {
            BizDrugIncompatibilityStandard r = inv.getArgument(0);
            r.setId(100L);
            return 1;
        });
        when(companionMapper.insertBizDrugIncompatibilityCompanion(any())).thenReturn(1);

        assertEquals(1, service.insertBizDrugIncompatibilityStandard(sampleInsert()));
        verify(companionMapper, atLeastOnce()).insertBizDrugIncompatibilityCompanion(any());
    }

    @Test
    @DisplayName("已同步禁止修改")
    void updateSyncedThrows()
    {
        when(standardMapper.selectBizDrugIncompatibilityStandardById(9L)).thenReturn(mainOnly(9L, 1));

        BizDrugIncompatibilityStandard in = sampleInsert();
        in.setId(9L);
        assertThrows(ServiceException.class, () -> service.updateBizDrugIncompatibilityStandard(in));
        verify(standardMapper, never()).updateBizDrugIncompatibilityStandard(any());
    }

    @Test
    @DisplayName("未同步修改替换子表")
    void updateReplacesCompanions()
    {
        when(standardMapper.selectBizDrugIncompatibilityStandardById(11L)).thenReturn(mainOnly(11L, 0));
        when(standardMapper.updateBizDrugIncompatibilityStandard(any())).thenReturn(1);
        when(companionMapper.deleteBizDrugIncompatibilityCompanionByStandardId(11L)).thenReturn(1);
        when(companionMapper.insertBizDrugIncompatibilityCompanion(any())).thenReturn(1);

        BizDrugIncompatibilityStandard in = sampleInsert();
        in.setId(11L);
        assertEquals(1, service.updateBizDrugIncompatibilityStandard(in));
        verify(companionMapper).deleteBizDrugIncompatibilityCompanionByStandardId(11L);
    }

    @Test
    @DisplayName("同步成功写 file_id 并删除临时 md")
    void syncKb()
    {
        BizDrugIncompatibilityStandard db = mainOnly(3L, 0);
        when(standardMapper.selectBizDrugIncompatibilityStandardById(3L)).thenReturn(db);
        when(drugIncompatibilityKbMarkdown.generateForSync(db)).thenReturn(Paths.get("药物禁配标准_3.md"));
        when(kbApiProperties.getDefaultKnowledgeBase()).thenReturn("default");
        when(knowledgeBaseClient.uploadFile(any(File.class), eq("药物禁配标准_3.md"), eq("default"), eq("药物禁配标准")))
                .thenReturn("FILE-3");
        when(standardMapper.updateBizDrugIncompatibilityStandard(any())).thenReturn(1);

        assertEquals(1, service.syncKb(3L));
        verify(knowledgeBaseClient).uploadFile(any(File.class), eq("药物禁配标准_3.md"), eq("default"), eq("药物禁配标准"));
        verify(kbMarkdownGenerator).deleteQuietly(Paths.get("药物禁配标准_3.md"));
    }

    @Test
    @DisplayName("移出成功")
    void removeKb()
    {
        BizDrugIncompatibilityStandard db = mainOnly(13L, 1);
        db.setKbDocId("DOC-13");
        when(standardMapper.selectBizDrugIncompatibilityStandardById(13L)).thenReturn(db);
        when(standardMapper.updateBizDrugIncompatibilityStandard(any())).thenReturn(1);

        assertEquals(1, service.removeKb(13L));
        verify(knowledgeBaseClient).deleteFile("DOC-13");
    }

    @Test
    @DisplayName("已同步禁止删")
    void deleteSyncedThrows()
    {
        when(standardMapper.selectBizDrugIncompatibilityStandardById(20L)).thenReturn(mainOnly(20L, 1));
        assertThrows(ServiceException.class, () -> service.deleteBizDrugIncompatibilityStandardByIds(new Long[] { 20L }));
        verify(standardMapper, never()).deleteBizDrugIncompatibilityStandardByIds(any());
    }

    @Test
    @DisplayName("详情带子表")
    void detailLoadsCompanions()
    {
        when(standardMapper.selectBizDrugIncompatibilityStandardById(5L)).thenReturn(mainOnly(5L, 0));
        when(companionMapper.selectBizDrugIncompatibilityCompanionListByStandardId(5L))
                .thenReturn(Collections.singletonList(compRow("配伍A")));

        BizDrugIncompatibilityStandard r = service.selectBizDrugIncompatibilityStandardById(5L);
        assertEquals(1, r.getCompanions().size());
    }

    private static BizDrugIncompatibilityCompanion compRow(String n)
    {
        BizDrugIncompatibilityCompanion c = new BizDrugIncompatibilityCompanion();
        c.setCompanionDrugName(n);
        return c;
    }

    private static BizDrugIncompatibilityStandard mainOnly(Long id, int kb)
    {
        BizDrugIncompatibilityStandard r = new BizDrugIncompatibilityStandard();
        r.setId(id);
        r.setMainDrugName("主");
        r.setKbSyncStatus(kb);
        r.setKbDocId(kb == 1 ? "LOCAL-" + id : null);
        return r;
    }

    private static BizDrugIncompatibilityStandard sampleInsert()
    {
        BizDrugIncompatibilityStandard r = new BizDrugIncompatibilityStandard();
        r.setMainDrugName("主药一");
        BizDrugIncompatibilityCompanion c = new BizDrugIncompatibilityCompanion();
        c.setCompanionDrugName("配伍一");
        r.setCompanions(Collections.singletonList(c));
        return r;
    }
}
