package com.ruoyi.ccdi.project.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.project.domain.CcdiProject;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedPurchaseDetailQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedPurchaseQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedRecruitmentDetailQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedRecruitmentQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedTransferDetailQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedTransferQueryDTO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedPurchaseListItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedPurchaseListVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedRecruitmentListItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedRecruitmentListVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedTransferListItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedTransferListVO;
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
import com.ruoyi.ccdi.project.mapper.CcdiProjectSpecialCheckMapper;
import com.ruoyi.common.exception.ServiceException;
import java.util.List;
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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
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.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class CcdiProjectSpecialCheckExtendedQueryServiceImplTest {

    @InjectMocks
    private CcdiProjectSpecialCheckServiceImpl service;

    @Mock
    private CcdiProjectSpecialCheckMapper specialCheckMapper;

    @Mock
    private CcdiProjectMapper projectMapper;

    @Test
    void shouldThrowProjectNotFoundForExtendedQueries() {
        when(projectMapper.selectById(99L)).thenReturn(null);

        ServiceException purchaseListException = assertThrows(
            ServiceException.class,
            () -> service.getExtendedPurchaseList(buildPurchaseQuery(99L, 1, 10))
        );
        ServiceException purchaseDetailException = assertThrows(
            ServiceException.class,
            () -> service.getExtendedPurchaseDetail(buildPurchaseDetailQuery(99L, "CG-001"))
        );
        ServiceException recruitmentListException = assertThrows(
            ServiceException.class,
            () -> service.getExtendedRecruitmentList(buildRecruitmentQuery(99L, "张三", 1, 10))
        );
        ServiceException transferDetailException = assertThrows(
            ServiceException.class,
            () -> service.getExtendedTransferDetail(buildTransferDetailQuery(99L, 1L))
        );

        assertEquals("项目不存在", purchaseListException.getMessage());
        assertEquals("项目不存在", purchaseDetailException.getMessage());
        assertEquals("项目不存在", recruitmentListException.getMessage());
        assertEquals("项目不存在", transferDetailException.getMessage());
    }

    @Test
    void shouldBuildPurchaseListRowsAndTotalFromPage() {
        when(projectMapper.selectById(40L)).thenReturn(buildProject(40L));

        Page<CcdiProjectExtendedPurchaseListItemVO> page = new Page<>(2, 5, 8);
        CcdiProjectExtendedPurchaseListItemVO item = new CcdiProjectExtendedPurchaseListItemVO();
        item.setPurchaseId("CG-001");
        page.setRecords(List.of(item));
        when(specialCheckMapper.selectExtendedPurchasePage(any(), any())).thenReturn(page);

        CcdiProjectExtendedPurchaseListVO result = service.getExtendedPurchaseList(buildPurchaseQuery(40L, 2, 5));

        assertNotNull(result.getRows());
        assertEquals(1, result.getRows().size());
        assertEquals(8L, result.getTotal());

        ArgumentCaptor<Page<CcdiProjectExtendedPurchaseListItemVO>> pageCaptor = ArgumentCaptor.forClass(Page.class);
        verify(specialCheckMapper).selectExtendedPurchasePage(pageCaptor.capture(), any());
        assertEquals(2L, pageCaptor.getValue().getCurrent());
        assertEquals(5L, pageCaptor.getValue().getSize());
    }

    @Test
    void shouldReturnEmptyRecruitmentAndTransferRowsInsteadOfNull() {
        when(projectMapper.selectById(40L)).thenReturn(buildProject(40L));
        when(specialCheckMapper.selectExtendedRecruitmentPage(any(), any())).thenReturn(new Page<>(1, 10, 0));
        when(specialCheckMapper.selectExtendedTransferPage(any(), any())).thenReturn(new Page<>(1, 10, 0));

        CcdiProjectExtendedRecruitmentListVO recruitmentResult =
            service.getExtendedRecruitmentList(buildRecruitmentQuery(40L, "李四", 1, 10));
        CcdiProjectExtendedTransferListVO transferResult = service.getExtendedTransferList(buildTransferQuery(40L, 1, 10));

        assertNotNull(recruitmentResult.getRows());
        assertEquals(0, recruitmentResult.getRows().size());
        assertEquals(0L, recruitmentResult.getTotal());
        assertNotNull(transferResult.getRows());
        assertEquals(0, transferResult.getRows().size());
        assertEquals(0L, transferResult.getTotal());
    }

    @Test
    void shouldPassInterviewerNameAndPaginationToRecruitmentMapper() {
        when(projectMapper.selectById(40L)).thenReturn(buildProject(40L));

        Page<CcdiProjectExtendedRecruitmentListItemVO> page = new Page<>(3, 4, 2);
        page.setRecords(List.of(new CcdiProjectExtendedRecruitmentListItemVO()));
        when(specialCheckMapper.selectExtendedRecruitmentPage(any(), any())).thenReturn(page);

        CcdiProjectExtendedRecruitmentQueryDTO queryDTO = buildRecruitmentQuery(40L, "王五", 3, 4);
        CcdiProjectExtendedRecruitmentListVO result = service.getExtendedRecruitmentList(queryDTO);

        assertEquals(2L, result.getTotal());
        ArgumentCaptor<Page<CcdiProjectExtendedRecruitmentListItemVO>> pageCaptor = ArgumentCaptor.forClass(Page.class);
        ArgumentCaptor<CcdiProjectExtendedRecruitmentQueryDTO> queryCaptor = ArgumentCaptor.forClass(
            CcdiProjectExtendedRecruitmentQueryDTO.class
        );
        verify(specialCheckMapper).selectExtendedRecruitmentPage(pageCaptor.capture(), queryCaptor.capture());
        assertEquals(3L, pageCaptor.getValue().getCurrent());
        assertEquals(4L, pageCaptor.getValue().getSize());
        assertEquals("王五", queryCaptor.getValue().getInterviewerName());
    }

    @Test
    void shouldThrowClearErrorWhenExtendedDetailDoesNotBelongToProjectScope() {
        when(projectMapper.selectById(40L)).thenReturn(buildProject(40L));
        when(specialCheckMapper.selectExtendedPurchaseDetail(40L, "CG-001")).thenReturn(null);
        when(specialCheckMapper.selectExtendedRecruitmentDetail(40L, "ZP-001")).thenReturn(null);
        when(specialCheckMapper.selectExtendedTransferDetail(40L, 1L)).thenReturn(null);

        ServiceException purchaseException = assertThrows(
            ServiceException.class,
            () -> service.getExtendedPurchaseDetail(buildPurchaseDetailQuery(40L, "CG-001"))
        );
        ServiceException recruitmentException = assertThrows(
            ServiceException.class,
            () -> service.getExtendedRecruitmentDetail(buildRecruitmentDetailQuery(40L, "ZP-001"))
        );
        ServiceException transferException = assertThrows(
            ServiceException.class,
            () -> service.getExtendedTransferDetail(buildTransferDetailQuery(40L, 1L))
        );

        assertEquals("当前记录不属于该项目专项核查范围", purchaseException.getMessage());
        assertEquals("当前记录不属于该项目专项核查范围", recruitmentException.getMessage());
        assertEquals("当前记录不属于该项目专项核查范围", transferException.getMessage());
    }

    private CcdiProject buildProject(Long projectId) {
        CcdiProject project = new CcdiProject();
        project.setProjectId(projectId);
        return project;
    }

    private CcdiProjectExtendedPurchaseQueryDTO buildPurchaseQuery(Long projectId, int pageNum, int pageSize) {
        CcdiProjectExtendedPurchaseQueryDTO queryDTO = new CcdiProjectExtendedPurchaseQueryDTO();
        queryDTO.setProjectId(projectId);
        queryDTO.setPageNum(pageNum);
        queryDTO.setPageSize(pageSize);
        return queryDTO;
    }

    private CcdiProjectExtendedPurchaseDetailQueryDTO buildPurchaseDetailQuery(Long projectId, String purchaseId) {
        CcdiProjectExtendedPurchaseDetailQueryDTO queryDTO = new CcdiProjectExtendedPurchaseDetailQueryDTO();
        queryDTO.setProjectId(projectId);
        queryDTO.setPurchaseId(purchaseId);
        return queryDTO;
    }

    private CcdiProjectExtendedRecruitmentQueryDTO buildRecruitmentQuery(
        Long projectId,
        String interviewerName,
        int pageNum,
        int pageSize
    ) {
        CcdiProjectExtendedRecruitmentQueryDTO queryDTO = new CcdiProjectExtendedRecruitmentQueryDTO();
        queryDTO.setProjectId(projectId);
        queryDTO.setInterviewerName(interviewerName);
        queryDTO.setPageNum(pageNum);
        queryDTO.setPageSize(pageSize);
        return queryDTO;
    }

    private CcdiProjectExtendedRecruitmentDetailQueryDTO buildRecruitmentDetailQuery(Long projectId, String recruitId) {
        CcdiProjectExtendedRecruitmentDetailQueryDTO queryDTO = new CcdiProjectExtendedRecruitmentDetailQueryDTO();
        queryDTO.setProjectId(projectId);
        queryDTO.setRecruitId(recruitId);
        return queryDTO;
    }

    private CcdiProjectExtendedTransferQueryDTO buildTransferQuery(Long projectId, int pageNum, int pageSize) {
        CcdiProjectExtendedTransferQueryDTO queryDTO = new CcdiProjectExtendedTransferQueryDTO();
        queryDTO.setProjectId(projectId);
        queryDTO.setPageNum(pageNum);
        queryDTO.setPageSize(pageSize);
        return queryDTO;
    }

    private CcdiProjectExtendedTransferDetailQueryDTO buildTransferDetailQuery(Long projectId, Long id) {
        CcdiProjectExtendedTransferDetailQueryDTO queryDTO = new CcdiProjectExtendedTransferDetailQueryDTO();
        queryDTO.setProjectId(projectId);
        queryDTO.setId(id);
        return queryDTO;
    }
}
