package com.ruoyi.info.collection.service;

import com.ruoyi.info.collection.domain.CcdiAccountInfo;
import com.ruoyi.info.collection.domain.CcdiBaseStaff;
import com.ruoyi.info.collection.domain.dto.CcdiAccountInfoAddDTO;
import com.ruoyi.info.collection.domain.excel.CcdiAccountInfoExcel;
import com.ruoyi.info.collection.mapper.CcdiAccountInfoMapper;
import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper;
import com.ruoyi.info.collection.mapper.CcdiStaffFmyRelationMapper;
import com.ruoyi.info.collection.service.impl.CcdiAccountInfoServiceImpl;
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.beans.BeanWrapperImpl;

import java.math.BigDecimal;
import java.util.List;
import java.util.Date;

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

@ExtendWith(MockitoExtension.class)
class CcdiAccountInfoServiceImplTest {

    @InjectMocks
    private CcdiAccountInfoServiceImpl service;

    @Mock
    private CcdiAccountInfoMapper accountInfoMapper;

    @Mock
    private CcdiBaseStaffMapper baseStaffMapper;

    @Mock
    private CcdiStaffFmyRelationMapper staffFmyRelationMapper;

    @Test
    void insertExternalAccount_shouldPersistAnalysisFieldsOnAccountInfo() {
        CcdiAccountInfoAddDTO dto = buildBaseAddDto();
        dto.setOwnerType("EXTERNAL");
        dto.setOwnerId("330101199001010011");
        dto.setBankScope("EXTERNAL");
        dto.setIsActualControl(0);
        dto.setAvgMonthTxnCount(6);
        dto.setAvgMonthTxnAmount(new BigDecimal("1234.56"));
        dto.setTxnFrequencyLevel("HIGH");
        dto.setDebitSingleMaxAmount(new BigDecimal("100.00"));
        dto.setCreditSingleMaxAmount(new BigDecimal("200.00"));
        dto.setDebitDailyMaxAmount(new BigDecimal("300.00"));
        dto.setCreditDailyMaxAmount(new BigDecimal("400.00"));
        dto.setTxnRiskLevel("MEDIUM");

        when(accountInfoMapper.selectCount(any())).thenReturn(0L);
        when(accountInfoMapper.insert(any(CcdiAccountInfo.class))).thenReturn(1);

        service.insertAccountInfo(dto);

        ArgumentCaptor<CcdiAccountInfo> captor = ArgumentCaptor.forClass(CcdiAccountInfo.class);
        verify(accountInfoMapper).insert(captor.capture());
        BeanWrapperImpl wrapper = new BeanWrapperImpl(captor.getValue());
        assertEquals(0, wrapper.getPropertyValue("isActualControl"));
        assertEquals(6, wrapper.getPropertyValue("avgMonthTxnCount"));
        assertEquals(new BigDecimal("1234.56"), wrapper.getPropertyValue("avgMonthTxnAmount"));
        assertEquals("HIGH", wrapper.getPropertyValue("txnFrequencyLevel"));
        assertEquals("MEDIUM", wrapper.getPropertyValue("txnRiskLevel"));
    }

    @Test
    void insertInternalAccount_shouldClearAnalysisFieldsOnAccountInfo() {
        CcdiAccountInfoAddDTO dto = buildBaseAddDto();
        dto.setOwnerType("EMPLOYEE");
        dto.setOwnerId("330101199001010022");
        dto.setBankScope("INTERNAL");
        dto.setIsActualControl(1);
        dto.setAvgMonthTxnCount(8);
        dto.setAvgMonthTxnAmount(new BigDecimal("9988.66"));
        dto.setTxnFrequencyLevel("HIGH");
        dto.setDebitSingleMaxAmount(new BigDecimal("111.11"));
        dto.setCreditSingleMaxAmount(new BigDecimal("222.22"));
        dto.setDebitDailyMaxAmount(new BigDecimal("333.33"));
        dto.setCreditDailyMaxAmount(new BigDecimal("444.44"));
        dto.setTxnRiskLevel("HIGH");

        CcdiBaseStaff staff = new CcdiBaseStaff();
        staff.setIdCard(dto.getOwnerId());

        when(baseStaffMapper.selectOne(any())).thenReturn(staff);
        when(accountInfoMapper.selectCount(any())).thenReturn(0L);
        when(accountInfoMapper.insert(any(CcdiAccountInfo.class))).thenReturn(1);

        service.insertAccountInfo(dto);

        ArgumentCaptor<CcdiAccountInfo> captor = ArgumentCaptor.forClass(CcdiAccountInfo.class);
        verify(accountInfoMapper).insert(captor.capture());
        BeanWrapperImpl wrapper = new BeanWrapperImpl(captor.getValue());
        assertNull(wrapper.getPropertyValue("isActualControl"));
        assertNull(wrapper.getPropertyValue("avgMonthTxnCount"));
        assertNull(wrapper.getPropertyValue("avgMonthTxnAmount"));
        assertNull(wrapper.getPropertyValue("txnFrequencyLevel"));
        assertNull(wrapper.getPropertyValue("debitSingleMaxAmount"));
        assertNull(wrapper.getPropertyValue("creditSingleMaxAmount"));
        assertNull(wrapper.getPropertyValue("debitDailyMaxAmount"));
        assertNull(wrapper.getPropertyValue("creditDailyMaxAmount"));
        assertNull(wrapper.getPropertyValue("txnRiskLevel"));
    }

    @Test
    void insertInternalIntermediaryAccount_shouldForceHighRiskLevelOnAccountInfo() {
        CcdiAccountInfoAddDTO dto = buildBaseAddDto();
        dto.setOwnerType("INTERMEDIARY");
        dto.setOwnerId("91330100MA00000001");
        dto.setBankScope("INTERNAL");
        dto.setIsActualControl(1);
        dto.setAvgMonthTxnCount(8);
        dto.setAvgMonthTxnAmount(new BigDecimal("9988.66"));
        dto.setTxnFrequencyLevel("HIGH");
        dto.setDebitSingleMaxAmount(new BigDecimal("111.11"));
        dto.setCreditSingleMaxAmount(new BigDecimal("222.22"));
        dto.setDebitDailyMaxAmount(new BigDecimal("333.33"));
        dto.setCreditDailyMaxAmount(new BigDecimal("444.44"));
        dto.setTxnRiskLevel("LOW");

        when(accountInfoMapper.selectCount(any())).thenReturn(0L);
        when(accountInfoMapper.insert(any(CcdiAccountInfo.class))).thenReturn(1);

        service.insertAccountInfo(dto);

        ArgumentCaptor<CcdiAccountInfo> captor = ArgumentCaptor.forClass(CcdiAccountInfo.class);
        verify(accountInfoMapper).insert(captor.capture());
        BeanWrapperImpl wrapper = new BeanWrapperImpl(captor.getValue());
        assertNull(wrapper.getPropertyValue("isActualControl"));
        assertNull(wrapper.getPropertyValue("avgMonthTxnCount"));
        assertNull(wrapper.getPropertyValue("avgMonthTxnAmount"));
        assertNull(wrapper.getPropertyValue("txnFrequencyLevel"));
        assertEquals("HIGH", wrapper.getPropertyValue("txnRiskLevel"));
    }

    @Test
    void importExternalIntermediaryAccount_shouldForceHighRiskLevelOnAccountInfo() {
        CcdiAccountInfoExcel excel = new CcdiAccountInfoExcel();
        excel.setOwnerType("中介");
        excel.setOwnerId("91330100MA00000002");
        excel.setAccountName("测试中介");
        excel.setAccountNo("6222024000000099");
        excel.setAccountType("银行账户");
        excel.setBankScope("行外");
        excel.setOpenBank("中国银行");
        excel.setBankCode("BOC");
        excel.setCurrency("CNY");
        excel.setStatus("正常");
        excel.setEffectiveDate("2026-07-10");
        excel.setTxnRiskLevel("LOW");

        when(accountInfoMapper.selectOne(any())).thenReturn(null);
        when(accountInfoMapper.selectCount(any())).thenReturn(0L);
        when(accountInfoMapper.insert(any(CcdiAccountInfo.class))).thenReturn(1);

        service.importAccountInfo(List.of(excel), false);

        ArgumentCaptor<CcdiAccountInfo> captor = ArgumentCaptor.forClass(CcdiAccountInfo.class);
        verify(accountInfoMapper).insert(captor.capture());
        assertEquals("HIGH", captor.getValue().getTxnRiskLevel());
    }

    private CcdiAccountInfoAddDTO buildBaseAddDto() {
        CcdiAccountInfoAddDTO dto = new CcdiAccountInfoAddDTO();
        dto.setAccountNo("6222024000000001");
        dto.setAccountType("BANK");
        dto.setAccountName("测试账户");
        dto.setOpenBank("中国银行");
        dto.setBankCode("BOC");
        dto.setCurrency("CNY");
        dto.setStatus(1);
        dto.setEffectiveDate(new Date());
        return dto;
    }
}
