package com.ruoyi.info.collection.service;

import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo;
import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoAddDTO;
import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoEditDTO;
import com.ruoyi.info.collection.domain.vo.CcdiEnterpriseBaseInfoVO;
import com.ruoyi.info.collection.mapper.CcdiCustEnterpriseRelationMapper;
import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper;
import com.ruoyi.info.collection.mapper.CcdiIntermediaryEnterpriseRelationMapper;
import com.ruoyi.info.collection.mapper.CcdiStaffEnterpriseRelationMapper;
import com.ruoyi.info.collection.service.impl.CcdiEnterpriseBaseInfoServiceImpl;
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 org.springframework.data.redis.core.RedisTemplate;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class CcdiEnterpriseBaseInfoServiceImplTest {

    @InjectMocks
    private CcdiEnterpriseBaseInfoServiceImpl service;

    @Mock
    private CcdiEnterpriseBaseInfoMapper enterpriseBaseInfoMapper;

    @Mock
    private CcdiStaffEnterpriseRelationMapper staffEnterpriseRelationMapper;

    @Mock
    private CcdiCustEnterpriseRelationMapper custEnterpriseRelationMapper;

    @Mock
    private CcdiIntermediaryEnterpriseRelationMapper intermediaryEnterpriseRelationMapper;

    @Mock
    private ICcdiEnterpriseBaseInfoImportService enterpriseBaseInfoImportService;

    @Mock
    private RedisTemplate<String, Object> redisTemplate;

    @Test
    void insertEnterpriseBaseInfo_shouldPersistWhenSocialCreditCodeIsUnique() {
        CcdiEnterpriseBaseInfoAddDTO addDTO = buildAddDto();
        when(enterpriseBaseInfoMapper.selectById(addDTO.getSocialCreditCode())).thenReturn(null);
        when(enterpriseBaseInfoMapper.insert(any(CcdiEnterpriseBaseInfo.class))).thenReturn(1);

        int result = service.insertEnterpriseBaseInfo(addDTO);

        assertEquals(1, result);
        ArgumentCaptor<CcdiEnterpriseBaseInfo> captor = ArgumentCaptor.forClass(CcdiEnterpriseBaseInfo.class);
        verify(enterpriseBaseInfoMapper).insert(captor.capture());
        assertEquals("测试企业", captor.getValue().getEnterpriseName());
        assertEquals("GENERAL", captor.getValue().getEntSource());
    }

    @Test
    void insertEnterpriseBaseInfo_shouldSetManualDataSourceAndAllowBlankStatus() {
        CcdiEnterpriseBaseInfoAddDTO addDTO = buildAddDto();
        addDTO.setStatus(null);
        addDTO.setDataSource("API");
        when(enterpriseBaseInfoMapper.selectById(addDTO.getSocialCreditCode())).thenReturn(null);
        when(enterpriseBaseInfoMapper.insert(any(CcdiEnterpriseBaseInfo.class))).thenReturn(1);

        int result = service.insertEnterpriseBaseInfo(addDTO);

        assertEquals(1, result);
        ArgumentCaptor<CcdiEnterpriseBaseInfo> captor = ArgumentCaptor.forClass(CcdiEnterpriseBaseInfo.class);
        verify(enterpriseBaseInfoMapper).insert(captor.capture());
        assertEquals("MANUAL", captor.getValue().getDataSource());
        assertNull(captor.getValue().getStatus());
    }

    @Test
    void insertEnterpriseBaseInfo_shouldRejectInvalidRiskLevel() {
        CcdiEnterpriseBaseInfoAddDTO addDTO = buildAddDto();
        addDTO.setRiskLevel("9");
        when(enterpriseBaseInfoMapper.selectById(addDTO.getSocialCreditCode())).thenReturn(null);

        RuntimeException exception = assertThrows(RuntimeException.class,
                () -> service.insertEnterpriseBaseInfo(addDTO));

        assertEquals("风险等级不在允许范围内", exception.getMessage());
    }

    @Test
    void updateEnterpriseBaseInfo_shouldRejectWhenRecordMissing() {
        CcdiEnterpriseBaseInfoEditDTO editDTO = buildEditDto();
        when(enterpriseBaseInfoMapper.selectById(editDTO.getSocialCreditCode())).thenReturn(null);

        RuntimeException exception = assertThrows(RuntimeException.class,
                () -> service.updateEnterpriseBaseInfo(editDTO));

        assertEquals("实体库记录不存在", exception.getMessage());
    }

    @Test
    void updateEnterpriseBaseInfo_shouldKeepExistingDataSource() {
        CcdiEnterpriseBaseInfoEditDTO editDTO = buildEditDto();
        editDTO.setDataSource("API");
        CcdiEnterpriseBaseInfo existing = new CcdiEnterpriseBaseInfo();
        existing.setSocialCreditCode(editDTO.getSocialCreditCode());
        existing.setDataSource("MANUAL");
        when(enterpriseBaseInfoMapper.selectById(editDTO.getSocialCreditCode())).thenReturn(existing);
        when(enterpriseBaseInfoMapper.updateById(any(CcdiEnterpriseBaseInfo.class))).thenReturn(1);

        int result = service.updateEnterpriseBaseInfo(editDTO);

        assertEquals(1, result);
        ArgumentCaptor<CcdiEnterpriseBaseInfo> captor = ArgumentCaptor.forClass(CcdiEnterpriseBaseInfo.class);
        verify(enterpriseBaseInfoMapper).updateById(captor.capture());
        assertEquals("MANUAL", captor.getValue().getDataSource());
    }

    @Test
    void selectEnterpriseBaseInfoById_shouldConvertEntityToVo() {
        CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo();
        entity.setSocialCreditCode("91310000123456789A");
        entity.setEnterpriseName("测试企业");
        entity.setRiskLevel("1");
        entity.setEntSource("GENERAL");
        when(enterpriseBaseInfoMapper.selectById("91310000123456789A")).thenReturn(entity);

        CcdiEnterpriseBaseInfoVO vo = service.selectEnterpriseBaseInfoById("91310000123456789A");

        assertNotNull(vo);
        assertEquals("测试企业", vo.getEnterpriseName());
        assertEquals("1", vo.getRiskLevel());
    }

    @Test
    void deleteEnterpriseBaseInfoByIds_shouldDeleteInBatch() {
        when(staffEnterpriseRelationMapper.selectCount(any())).thenReturn(0L);
        when(custEnterpriseRelationMapper.selectCount(any())).thenReturn(0L);
        when(intermediaryEnterpriseRelationMapper.selectCount(any())).thenReturn(0L);
        when(enterpriseBaseInfoMapper.deleteBatchIds(java.util.List.of("91310000123456789A", "91310000123456789B")))
                .thenReturn(2);

        int result = service.deleteEnterpriseBaseInfoByIds(new String[]{"91310000123456789A", "91310000123456789B"});

        assertEquals(2, result);
        verify(enterpriseBaseInfoMapper).deleteBatchIds(java.util.List.of("91310000123456789A", "91310000123456789B"));
    }

    @Test
    void deleteEnterpriseBaseInfoByIds_shouldRejectWhenStaffRelationExists() {
        when(staffEnterpriseRelationMapper.selectCount(any())).thenReturn(1L);
        when(custEnterpriseRelationMapper.selectCount(any())).thenReturn(0L);
        when(intermediaryEnterpriseRelationMapper.selectCount(any())).thenReturn(0L);

        RuntimeException exception = assertThrows(RuntimeException.class,
                () -> service.deleteEnterpriseBaseInfoByIds(new String[]{"91310000123456789A"}));

        assertEquals("统一社会信用代码[91310000123456789A]已关联员工，删除失败", exception.getMessage());
    }

    @Test
    void deleteEnterpriseBaseInfoByIds_shouldRejectWhenMultipleRelationsExist() {
        when(staffEnterpriseRelationMapper.selectCount(any())).thenReturn(1L);
        when(custEnterpriseRelationMapper.selectCount(any())).thenReturn(1L);
        when(intermediaryEnterpriseRelationMapper.selectCount(any())).thenReturn(1L);

        RuntimeException exception = assertThrows(RuntimeException.class,
                () -> service.deleteEnterpriseBaseInfoByIds(new String[]{"91310000123456789A"}));

        assertEquals("统一社会信用代码[91310000123456789A]已关联员工、信贷客户、中介，删除失败", exception.getMessage());
    }

    private CcdiEnterpriseBaseInfoAddDTO buildAddDto() {
        CcdiEnterpriseBaseInfoAddDTO dto = new CcdiEnterpriseBaseInfoAddDTO();
        dto.setSocialCreditCode("91310000123456789A");
        dto.setEnterpriseName("测试企业");
        dto.setEnterpriseType("有限责任公司");
        dto.setEnterpriseNature("民营企业");
        dto.setIndustryClass("制造业");
        dto.setIndustryName("电子设备");
        dto.setStatus("存续");
        dto.setRiskLevel("1");
        dto.setEntSource("GENERAL");
        dto.setDataSource("MANUAL");
        return dto;
    }

    private CcdiEnterpriseBaseInfoEditDTO buildEditDto() {
        CcdiEnterpriseBaseInfoEditDTO dto = new CcdiEnterpriseBaseInfoEditDTO();
        dto.setSocialCreditCode("91310000123456789A");
        dto.setEnterpriseName("测试企业");
        dto.setStatus("存续");
        dto.setRiskLevel("1");
        dto.setEntSource("GENERAL");
        dto.setDataSource("MANUAL");
        return dto;
    }
}
