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

import com.ruoyi.ccdi.project.domain.CcdiProject;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectFamilyAssetLiabilityDetailQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectFamilyAssetLiabilityListQueryDTO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityDetailVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityListItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityListVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetDetailVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyDebtDetailVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyIncomeDetailVO;
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
import com.ruoyi.ccdi.project.mapper.CcdiProjectSpecialCheckMapper;
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.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class CcdiProjectSpecialCheckServiceImplTest {

    @InjectMocks
    private CcdiProjectSpecialCheckServiceImpl service;

    @Mock
    private CcdiProjectSpecialCheckMapper specialCheckMapper;

    @Mock
    private CcdiProjectMapper projectMapper;

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

        assertThrows(ServiceException.class, () -> service.getFamilyAssetLiabilityList(buildListQuery(99L)));
        assertThrows(ServiceException.class, () -> service.getFamilyAssetLiabilityDetail(buildDetailQuery(99L, "3301")));
    }

    @Test
    void shouldReturnEmptyRowsWhenListMapperReturnsNull() {
        when(projectMapper.selectById(40L)).thenReturn(buildProject(40L));
        when(specialCheckMapper.selectFamilyAssetLiabilityList(40L)).thenReturn(null);

        CcdiProjectFamilyAssetLiabilityListVO result = service.getFamilyAssetLiabilityList(buildListQuery(40L));

        assertNotNull(result.getRows());
        assertEquals(0, result.getRows().size());
    }

    @Test
    void shouldThrowClearErrorWhenStaffDoesNotBelongToProjectScope() {
        when(projectMapper.selectById(40L)).thenReturn(buildProject(40L));
        when(specialCheckMapper.selectFamilyAssetLiabilityDetail(40L, "330102199001011234")).thenReturn(null);

        ServiceException exception = assertThrows(
            ServiceException.class,
            () -> service.getFamilyAssetLiabilityDetail(buildDetailQuery(40L, "330102199001011234"))
        );

        assertEquals("当前员工不属于该项目专项核查范围", exception.getMessage());
    }

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

        CcdiProjectFamilyAssetLiabilityListItemVO listItem = new CcdiProjectFamilyAssetLiabilityListItemVO();
        listItem.setStaffIdCard("330102199001011234");
        listItem.setTotalIncome(new BigDecimal("180000.00"));
        listItem.setTotalAsset(new BigDecimal("520000.00"));
        listItem.setTotalDebt(new BigDecimal("260000.00"));
        listItem.setComparisonAmount(new BigDecimal("440000.00"));
        listItem.setRiskLevelCode("RISK");
        listItem.setRiskLevelName("存在风险");
        when(specialCheckMapper.selectFamilyAssetLiabilityList(40L)).thenReturn(List.of(listItem));

        CcdiProjectFamilyAssetLiabilityDetailVO detailVO = new CcdiProjectFamilyAssetLiabilityDetailVO();
        detailVO.setIncomeDetail(new CcdiProjectFamilyIncomeDetailVO());
        detailVO.setAssetDetail(new CcdiProjectFamilyAssetDetailVO());
        detailVO.setDebtDetail(new CcdiProjectFamilyDebtDetailVO());
        detailVO.setSummary(listItem);
        when(specialCheckMapper.selectFamilyAssetLiabilityDetail(40L, "330102199001011234")).thenReturn(detailVO);

        CcdiProjectFamilyAssetLiabilityListVO listResult = service.getFamilyAssetLiabilityList(buildListQuery(40L));
        CcdiProjectFamilyAssetLiabilityDetailVO detailResult =
            service.getFamilyAssetLiabilityDetail(buildDetailQuery(40L, "330102199001011234"));

        assertEquals(listResult.getRows().getFirst().getTotalIncome(), detailResult.getSummary().getTotalIncome());
        assertEquals(listResult.getRows().getFirst().getTotalAsset(), detailResult.getSummary().getTotalAsset());
        assertEquals(listResult.getRows().getFirst().getTotalDebt(), detailResult.getSummary().getTotalDebt());
        assertEquals(
            listResult.getRows().getFirst().getComparisonAmount(),
            detailResult.getSummary().getComparisonAmount()
        );
        assertNotNull(detailResult.getAssetDetail().getItems());
        assertNotNull(detailResult.getDebtDetail().getItems());
        verify(specialCheckMapper).selectFamilyAssetLiabilityList(40L);
        verify(specialCheckMapper).selectFamilyAssetLiabilityDetail(40L, "330102199001011234");
    }

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

        CcdiProjectFamilyAssetLiabilityListItemVO summary = new CcdiProjectFamilyAssetLiabilityListItemVO();
        summary.setRiskLevelCode("MISSING_INFO");
        summary.setRiskLevelName("缺少信息");

        CcdiProjectFamilyAssetDetailVO assetDetail = new CcdiProjectFamilyAssetDetailVO();
        assetDetail.setMissingSelfAssetInfo(true);
        CcdiProjectFamilyDebtDetailVO debtDetail = new CcdiProjectFamilyDebtDetailVO();
        debtDetail.setMissingSelfDebtInfo(true);

        CcdiProjectFamilyAssetLiabilityDetailVO detailVO = new CcdiProjectFamilyAssetLiabilityDetailVO();
        detailVO.setIncomeDetail(new CcdiProjectFamilyIncomeDetailVO());
        detailVO.setAssetDetail(assetDetail);
        detailVO.setDebtDetail(debtDetail);
        detailVO.setSummary(summary);
        when(specialCheckMapper.selectFamilyAssetLiabilityDetail(40L, "330102199001011234")).thenReturn(detailVO);

        CcdiProjectFamilyAssetLiabilityDetailVO result =
            service.getFamilyAssetLiabilityDetail(buildDetailQuery(40L, "330102199001011234"));

        assertEquals("MISSING_INFO", result.getSummary().getRiskLevelCode());
        assertEquals("缺少信息", result.getSummary().getRiskLevelName());
        assertTrue(result.getAssetDetail().getMissingSelfAssetInfo());
        assertTrue(result.getDebtDetail().getMissingSelfDebtInfo());
    }

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

    private CcdiProjectFamilyAssetLiabilityListQueryDTO buildListQuery(Long projectId) {
        CcdiProjectFamilyAssetLiabilityListQueryDTO queryDTO = new CcdiProjectFamilyAssetLiabilityListQueryDTO();
        queryDTO.setProjectId(projectId);
        return queryDTO;
    }

    private CcdiProjectFamilyAssetLiabilityDetailQueryDTO buildDetailQuery(Long projectId, String staffIdCard) {
        CcdiProjectFamilyAssetLiabilityDetailQueryDTO queryDTO = new CcdiProjectFamilyAssetLiabilityDetailQueryDTO();
        queryDTO.setProjectId(projectId);
        queryDTO.setStaffIdCard(staffIdCard);
        return queryDTO;
    }
}
