package com.zt.plat.module.base.api.materialclasses;

import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesPageReqDTO;
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesRespDTO;
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesSaveReqDTO;
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesTreeRespDTO;
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesPageReqVO;
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesRespVO;
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesSaveReqVO;
import com.zt.plat.module.base.dal.dataobject.materialclasses.MaterialClassesDO;
import com.zt.plat.module.base.service.materialclasses.MaterialClassesService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.LocalDateTime;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class MaterialClassesApiImplTest {

    @InjectMocks
    private MaterialClassesApiImpl api;

    @Mock
    private MaterialClassesService materialClassesService;

    private MaterialClassesSaveReqDTO buildSaveReq() {
        MaterialClassesSaveReqDTO dto = new MaterialClassesSaveReqDTO();
        dto.setId(1L);
        dto.setParentId(0L);
        dto.setCode("CLS001");
        dto.setName("原材料");
        dto.setLevel(1L);
        dto.setRemark("顶级分类");
        return dto;
    }

    private MaterialClassesRespVO buildRespVO() {
        MaterialClassesRespVO respVO = new MaterialClassesRespVO();
        respVO.setId(1L);
        respVO.setParentId(0L);
        respVO.setCode("CLS001");
        respVO.setName("原材料");
        respVO.setLevel(1L);
        respVO.setRemark("顶级分类");
        respVO.setCreateTime(LocalDateTime.now());
        return respVO;
    }

    @Test
    void createMaterialClasses_shouldForwardToServiceAndReturnConvertedDto() {
        MaterialClassesSaveReqDTO reqDTO = buildSaveReq();
        MaterialClassesRespVO serviceResp = buildRespVO();
        when(materialClassesService.createMaterialClasses(any(MaterialClassesSaveReqVO.class)))
                .thenReturn(serviceResp);

        CommonResult<MaterialClassesRespDTO> result = api.createMaterialClasses(reqDTO);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getData().getName()).isEqualTo("原材料");

        ArgumentCaptor<MaterialClassesSaveReqVO> captor = ArgumentCaptor.forClass(MaterialClassesSaveReqVO.class);
        verify(materialClassesService).createMaterialClasses(captor.capture());
        MaterialClassesSaveReqVO passed = captor.getValue();
        assertThat(passed.getCode()).isEqualTo(reqDTO.getCode());
        assertThat(passed.getName()).isEqualTo(reqDTO.getName());
    }

    @Test
    void updateMaterialClasses_shouldInvokeService() {
        MaterialClassesSaveReqDTO reqDTO = buildSaveReq();

        CommonResult<Boolean> result = api.updateMaterialClasses(reqDTO);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getData()).isTrue();
        ArgumentCaptor<MaterialClassesSaveReqVO> captor = ArgumentCaptor.forClass(MaterialClassesSaveReqVO.class);
        verify(materialClassesService).updateMaterialClasses(captor.capture());
        assertThat(captor.getValue().getCode()).isEqualTo(reqDTO.getCode());
    }

    @Test
    void deleteMaterialClasses_shouldInvokeService() {
        CommonResult<Boolean> result = api.deleteMaterialClasses(5L);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getData()).isTrue();
        verify(materialClassesService).deleteMaterialClasses(5L);
    }

    @Test
    void deleteMaterialClassesList_shouldInvokeService() {
        List<Long> ids = List.of(3L, 4L);

        CommonResult<Boolean> result = api.deleteMaterialClassesList(ids);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getData()).isTrue();
        verify(materialClassesService).deleteMaterialClassesListByIds(ids);
    }

    @Test
    void getMaterialClasses_shouldConvertDoToDto() {
        MaterialClassesDO classesDO = new MaterialClassesDO();
        classesDO.setId(7L);
        classesDO.setName("辅料");
        when(materialClassesService.getMaterialClasses(7L)).thenReturn(classesDO);

        CommonResult<MaterialClassesRespDTO> result = api.getMaterialClasses(7L);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getData().getId()).isEqualTo(7L);
        assertThat(result.getData().getName()).isEqualTo("辅料");
    }

    @Test
    void getMaterialClassesPage_shouldConvertPageResult() {
        MaterialClassesDO classesDO = new MaterialClassesDO();
        classesDO.setId(8L);
        classesDO.setName("辅料");
        PageResult<MaterialClassesDO> page = new PageResult<>(List.of(classesDO), 1L);
        when(materialClassesService.getMaterialClassesPage(any(MaterialClassesPageReqVO.class)))
                .thenReturn(page);

        MaterialClassesPageReqDTO reqDTO = new MaterialClassesPageReqDTO();
        reqDTO.setName("辅料");

        CommonResult<PageResult<MaterialClassesRespDTO>> result = api.getMaterialClassesPage(reqDTO);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getData().getList()).hasSize(1);
        assertThat(result.getData().getList().get(0).getName()).isEqualTo("辅料");
        assertThat(result.getData().getTotal()).isEqualTo(1L);
    }

    @Test
    void getMaterialClassesTree_shouldAssembleHierarchy() {
        MaterialClassesDO root = new MaterialClassesDO();
        root.setId(1L);
        root.setParentId(0L);
        root.setName("根节点");

        MaterialClassesDO child = new MaterialClassesDO();
        child.setId(2L);
        child.setParentId(1L);
        child.setName("子节点");

        MaterialClassesDO orphan = new MaterialClassesDO();
        orphan.setId(3L);
        orphan.setParentId(99L);
        orphan.setName("孤儿节点");

        when(materialClassesService.getMaterialClassesList()).thenReturn(List.of(child, root, orphan));

        CommonResult<List<MaterialClassesTreeRespDTO>> result = api.getMaterialClassesTree();

        assertThat(result.isSuccess()).isTrue();
        List<MaterialClassesTreeRespDTO> tree = result.getData();
        assertThat(tree).hasSize(2);
        MaterialClassesTreeRespDTO rootNode = tree.get(0);
        assertThat(rootNode.getId()).isEqualTo(1L);
        assertThat(rootNode.getChildren()).hasSize(1);
        assertThat(rootNode.getChildren().get(0).getId()).isEqualTo(2L);

        MaterialClassesTreeRespDTO orphanNode = tree.get(1);
        assertThat(orphanNode.getId()).isEqualTo(3L);
        assertThat(orphanNode.getChildren()).isEmpty();
    }
}
