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.CcdiProjectAbnormalAccountQueryDTO;
import com.ruoyi.ccdi.project.domain.excel.CcdiProjectAbnormalAccountExcel;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectAbnormalAccountItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectAbnormalAccountPageVO;
import com.ruoyi.ccdi.project.mapper.CcdiBankTagResultMapper;
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
import com.ruoyi.ccdi.project.mapper.CcdiProjectOverviewEmployeeResultMapper;
import com.ruoyi.ccdi.project.mapper.CcdiProjectOverviewMapper;
import com.ruoyi.common.exception.ServiceException;
import java.math.BigDecimal;
import java.util.List;
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 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.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class CcdiProjectOverviewServiceAbnormalAccountTest {

    @InjectMocks
    private CcdiProjectOverviewServiceImpl service;

    @Mock
    private CcdiProjectOverviewMapper overviewMapper;

    @Mock
    private CcdiProjectMapper projectMapper;

    @Mock
    private CcdiProjectOverviewEmployeeResultMapper overviewEmployeeResultMapper;

    @Mock
    private CcdiBankTagResultMapper bankTagResultMapper;

    @Mock
    private CcdiProjectOverviewEmployeeResultBuilder overviewEmployeeResultBuilder;

    @Mock
    private CcdiProjectRiskDetailWorkbookExporter workbookExporter;

    @Test
    void shouldMapAbnormalAccountPageRowsAndTotal() {
        mockProjectExists(40L);

        CcdiProjectAbnormalAccountQueryDTO queryDTO = new CcdiProjectAbnormalAccountQueryDTO();
        queryDTO.setProjectId(40L);
        queryDTO.setPageNum(1);
        queryDTO.setPageSize(5);

        CcdiProjectAbnormalAccountItemVO item = new CcdiProjectAbnormalAccountItemVO();
        item.setAccountNo("6222000000000001");
        item.setAccountName("李四");
        item.setBankName("中国农业银行");
        item.setAbnormalType("突然销户");
        item.setAbnormalTime("2026-03-20");
        item.setStatus("已销户");
        item.setReasonDetail("账户6222000000000001销户前存在异常交易");
        item.setInvolvedAmount(new BigDecimal("120000.00"));

        Page<CcdiProjectAbnormalAccountItemVO> resultPage = new Page<>(1, 5);
        resultPage.setRecords(List.of(item));
        resultPage.setTotal(1L);
        when(overviewMapper.selectAbnormalAccountPage(any(Page.class), any(CcdiProjectAbnormalAccountQueryDTO.class)))
            .thenReturn(resultPage);

        CcdiProjectAbnormalAccountPageVO result = service.getAbnormalAccountPeople(queryDTO);

        assertEquals(1, result.getRows().size());
        assertEquals(1L, result.getTotal());
        assertEquals("6222000000000001", result.getRows().getFirst().getAccountNo());
        assertEquals("突然销户", result.getRows().getFirst().getAbnormalType());
        assertEquals("账户6222000000000001销户前存在异常交易", result.getRows().getFirst().getReasonDetail());
        assertEquals(new BigDecimal("120000.00"), result.getRows().getFirst().getInvolvedAmount());
        verify(overviewMapper).selectAbnormalAccountPage(
            argThat(page -> page.getCurrent() == 1L && page.getSize() == 5L),
            argThat(query -> query.getProjectId().equals(40L))
        );
    }

    @Test
    void shouldDefaultAbnormalAccountPageNumAndPageSizeToOneAndFive() {
        mockProjectExists(40L);

        Page<CcdiProjectAbnormalAccountItemVO> emptyPage = new Page<>(1, 5);
        emptyPage.setRecords(List.of());
        emptyPage.setTotal(0L);
        when(overviewMapper.selectAbnormalAccountPage(any(Page.class), any(CcdiProjectAbnormalAccountQueryDTO.class)))
            .thenReturn(emptyPage);

        CcdiProjectAbnormalAccountQueryDTO queryDTO = new CcdiProjectAbnormalAccountQueryDTO();
        queryDTO.setProjectId(40L);
        service.getAbnormalAccountPeople(queryDTO);

        verify(overviewMapper).selectAbnormalAccountPage(
            argThat(page -> page.getCurrent() == 1L && page.getSize() == 5L),
            any(CcdiProjectAbnormalAccountQueryDTO.class)
        );
    }

    @Test
    void shouldExportAbnormalAccountPeopleRows() {
        mockProjectExists(40L);

        CcdiProjectAbnormalAccountItemVO item = new CcdiProjectAbnormalAccountItemVO();
        item.setAccountNo("6222000000000002");
        item.setAccountName("王五");
        item.setBankName("中国银行");
        item.setAbnormalType("休眠账户大额启用");
        item.setAbnormalTime("2025-08-01");
        item.setStatus("正常");
        item.setReasonDetail("账户6222000000000002休眠后大额启用");
        item.setInvolvedAmount(new BigDecimal("500000.00"));
        when(overviewMapper.selectAbnormalAccountList(40L)).thenReturn(List.of(item));

        List<CcdiProjectAbnormalAccountExcel> rows = service.exportAbnormalAccountPeople(40L);

        assertEquals(1, rows.size());
        assertEquals("6222000000000002", rows.getFirst().getAccountNo());
        assertEquals("王五", rows.getFirst().getAccountName());
        assertEquals("中国银行", rows.getFirst().getBankName());
        assertEquals("休眠账户大额启用", rows.getFirst().getAbnormalType());
        assertEquals("2025-08-01", rows.getFirst().getAbnormalTime());
        assertEquals("正常", rows.getFirst().getStatus());
        assertEquals("账户6222000000000002休眠后大额启用", rows.getFirst().getReasonDetail());
        assertEquals(new BigDecimal("500000.00"), rows.getFirst().getInvolvedAmount());
        verify(overviewMapper).selectAbnormalAccountList(40L);
    }

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

        CcdiProjectAbnormalAccountQueryDTO queryDTO = new CcdiProjectAbnormalAccountQueryDTO();
        queryDTO.setProjectId(99L);

        assertThrows(ServiceException.class, () -> service.getAbnormalAccountPeople(queryDTO));
        assertThrows(ServiceException.class, () -> service.exportAbnormalAccountPeople(99L));
    }

    private void mockProjectExists(Long projectId) {
        CcdiProject project = new CcdiProject();
        project.setProjectId(projectId);
        when(projectMapper.selectById(projectId)).thenReturn(project);
    }
}
