package com.ruoyi.web.modules.entry.service;

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.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Date;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
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 com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.web.modules.account.domain.BizMember;
import com.ruoyi.web.modules.account.mapper.BizMemberMapper;
import com.ruoyi.web.modules.content.facade.IMerchantEntryAgreementFacade;
import com.ruoyi.web.modules.entry.constant.MerchantEntryApplyConstants;
import com.ruoyi.web.modules.entry.domain.BizMerchantEntryApply;
import com.ruoyi.web.modules.entry.dto.EntryApplyRejectDTO;
import com.ruoyi.web.modules.entry.dto.EntryApplyShopDTO;
import com.ruoyi.web.modules.entry.dto.EntryApplySubmitDTO;
import com.ruoyi.web.modules.entry.mapper.BizMerchantEntryApplyMapper;
import com.ruoyi.web.modules.entry.service.impl.MerchantEntryApplyServiceImpl;
import com.ruoyi.web.modules.entry.support.EntryApplyFormMapper;
import com.ruoyi.web.modules.finance.service.IShopFundService;
import com.ruoyi.web.modules.merchant.constant.MerchantConstants;
import com.ruoyi.web.modules.merchant.domain.BizMerchant;
import com.ruoyi.web.modules.merchant.mapper.BizMerchantMapper;
import com.ruoyi.web.modules.merchant.service.IMerchantAccountBindService;
import com.ruoyi.web.modules.store.mapper.BizShopMapper;
import com.ruoyi.web.modules.store.service.IShopService;
import com.ruoyi.web.modules.entry.support.MemberEntryMessageSupport;

/**
 * 商户入驻审核服务测试（MEA-UT）
 */
@ExtendWith(MockitoExtension.class)
class MerchantEntryApplyServiceImplTest
{
    @Mock
    private BizMerchantEntryApplyMapper applyMapper;

    @Mock
    private BizMerchantMapper merchantMapper;

    @Mock
    private BizShopMapper shopMapper;

    @Mock
    private BizMemberMapper memberMapper;

    @Mock
    private IMerchantEntryAgreementFacade agreementFacade;

    @Mock
    private IMerchantAccountBindService accountBindService;

    @Mock
    private IShopService shopService;

    @Mock
    private MemberEntryMessageSupport messageSupport;

    @Mock
    private ISysConfigService configService;

    @Mock
    private IShopFundService shopFundService;

    @InjectMocks
    private MerchantEntryApplyServiceImpl applyService;

    private BizMember member;

    @BeforeEach
    void setUp()
    {
        member = new BizMember();
        member.setMemberId(100L);
        member.setMemberCode("测试会员");
        member.setNickName("nick100");
    }

    @Test
    void submitApply_agreementNotAccepted_rejected()
    {
        EntryApplySubmitDTO dto = buildValidPersonDto();
        dto.setAgreementAccepted(false);
        org.mockito.Mockito.doThrow(new ServiceException("请先阅读并同意入驻协议"))
                .when(agreementFacade).assertAccepted(false);

        assertThrows(ServiceException.class, () -> applyService.submitApply(100L, dto));
        verify(applyMapper, never()).insert(any());
    }

    @Test
    void submitApply_pendingExists_rejected()
    {
        EntryApplySubmitDTO dto = buildValidPersonDto();
        when(applyMapper.countBlockingByMemberId(100L)).thenReturn(1);

        ServiceException ex = assertThrows(ServiceException.class, () -> applyService.submitApply(100L, dto));
        assertEquals(MerchantEntryApplyConstants.MSG_PENDING_EXISTS, ex.getMessage());
        verify(applyMapper, never()).insert(any());
    }

    @Test
    void submitApply_duplicateCreditCode_rejected()
    {
        EntryApplySubmitDTO dto = buildValidEnterpriseDto();
        when(applyMapper.countBlockingByMemberId(100L)).thenReturn(0);
        when(memberMapper.selectById(100L)).thenReturn(member);
        when(merchantMapper.countByCreditCode("91110000MA001", null)).thenReturn(1);

        assertThrows(ServiceException.class, () -> applyService.submitApply(100L, dto));
        verify(applyMapper, never()).insert(any());
    }

    @Test
    void submitApply_duplicateIdCard_rejected()
    {
        EntryApplySubmitDTO dto = buildValidPersonDto();
        when(applyMapper.countBlockingByMemberId(100L)).thenReturn(0);
        when(memberMapper.selectById(100L)).thenReturn(member);
        when(merchantMapper.countByIdCardNo("110101199001011234", null)).thenReturn(1);

        assertThrows(ServiceException.class, () -> applyService.submitApply(100L, dto));
        verify(applyMapper, never()).insert(any());
    }

    @Test
    void submitApply_success_pending()
    {
        EntryApplySubmitDTO dto = buildValidPersonDto();
        when(applyMapper.countBlockingByMemberId(100L)).thenReturn(0);
        when(memberMapper.selectById(100L)).thenReturn(member);
        when(merchantMapper.countByIdCardNo(any(), eq(null))).thenReturn(0);
        when(applyMapper.countByIdCardNoActive(any(), eq(null))).thenReturn(0);
        when(merchantMapper.countByMerchantName(any(), eq(null))).thenReturn(0);
        when(applyMapper.countByMerchantNameActive(any(), eq(null))).thenReturn(0);
        when(shopMapper.countByShopName(any(), eq(null))).thenReturn(0);
        when(applyMapper.countByShopNameActive(any(), eq(null))).thenReturn(0);
        when(applyMapper.insert(any())).thenAnswer(inv -> {
            BizMerchantEntryApply apply = inv.getArgument(0);
            apply.setApplyId(1L);
            return 1;
        });

        Map<String, Object> data = applyService.submitApply(100L, dto);

        assertEquals(MerchantEntryApplyConstants.STATUS_PENDING, data.get("applyStatus"));
        assertNotNull(data.get("applyNo"));
        verify(applyMapper).insert(any());
    }

    @Test
    void reject_emptyReason_rejected()
    {
        EntryApplyRejectDTO dto = new EntryApplyRejectDTO();
        dto.setApplyId(1L);
        dto.setRejectReason("");

        assertThrows(ServiceException.class, () -> applyService.reject(dto, "admin"));
    }

    @Test
    void reject_notPending_rejected()
    {
        BizMerchantEntryApply apply = pendingApply();
        apply.setApplyStatus(MerchantEntryApplyConstants.STATUS_APPROVED);
        when(applyMapper.selectById(1L)).thenReturn(apply);

        EntryApplyRejectDTO dto = new EntryApplyRejectDTO();
        dto.setApplyId(1L);
        dto.setRejectReason("资料不全");

        assertThrows(ServiceException.class, () -> applyService.reject(dto, "admin"));
        verify(messageSupport, never()).sendReject(any(), any(), any(), any());
    }

    @Test
    void reject_success()
    {
        when(applyMapper.selectById(1L)).thenReturn(pendingApply());

        EntryApplyRejectDTO dto = new EntryApplyRejectDTO();
        dto.setApplyId(1L);
        dto.setRejectReason("资料不全");

        applyService.reject(dto, "admin");

        verify(applyMapper).updateAuditResult(any());
        verify(messageSupport).sendReject(eq(100L), eq(1L), eq("EA20260101001"), eq("资料不全"));
    }

    @Test
    void completePublicity_seedsContactBankAccount()
    {
        EntryApplySubmitDTO dto = buildValidPersonDto();
        String formJson = EntryApplyFormMapper.toFormJson(dto);

        BizMerchantEntryApply apply = new BizMerchantEntryApply();
        apply.setApplyId(1L);
        apply.setApplyNo("EA20260101001");
        apply.setApplyStatus(MerchantEntryApplyConstants.STATUS_PUBLICITY);
        apply.setMerchantType(MerchantConstants.TYPE_PERSON);
        apply.setMemberId(100L);
        apply.setFormJson(formJson);
        apply.setPublicityEndTime(new Date(System.currentTimeMillis() - 1000));

        when(applyMapper.selectById(1L)).thenReturn(apply);
        when(memberMapper.selectById(100L)).thenReturn(member);
        when(merchantMapper.countByIdCardNo(any(), eq(null))).thenReturn(0);
        when(applyMapper.countByIdCardNoActive(any(), eq(1L))).thenReturn(0);
        when(merchantMapper.countByMerchantName(any(), eq(null))).thenReturn(0);
        when(applyMapper.countByMerchantNameActive(any(), eq(1L))).thenReturn(0);
        when(shopMapper.countByShopName(any(), eq(null))).thenReturn(0);
        when(applyMapper.countByShopNameActive(any(), eq(1L))).thenReturn(0);
        when(merchantMapper.insert(any())).thenAnswer(inv -> {
            BizMerchant m = inv.getArgument(0);
            m.setMerchantId(200L);
            return 1;
        });
        when(shopService.createShop(any(), eq("admin"))).thenReturn(301L);

        applyService.completePublicity(1L, "admin");

        verify(shopFundService).seedContactBankAccountFromEntry(eq(301L), eq("张三"), eq("6222020000000000"),
                eq("admin"));
    }

    private EntryApplySubmitDTO buildValidPersonDto()
    {
        EntryApplySubmitDTO dto = new EntryApplySubmitDTO();
        dto.setAgreementAccepted(true);
        BizMerchant subject = new BizMerchant();
        subject.setMerchantType(MerchantConstants.TYPE_PERSON);
        subject.setPersonName("张三");
        subject.setResidenceAddress("北京市朝阳区");
        subject.setGender("0");
        subject.setBirthDate(new Date());
        subject.setIdCardType(MerchantConstants.ID_TYPE_MAINLAND);
        subject.setIdCardNo("110101199001011234");
        subject.setIdValidType(MerchantConstants.VALID_PERIOD_LONG);
        subject.setIdCardFront("/profile/id/front.jpg");
        subject.setIdCardBack("/profile/id/back.jpg");
        subject.setContactName("张三");
        subject.setContactPhone("13800138000");
        subject.setContactEmail("zhang@test.com");
        subject.setBankName("工商银行");
        subject.setBankBranch("朝阳支行");
        subject.setBankAccount("6222020000000000");
        dto.setSubject(subject);
        BizMerchant biz = new BizMerchant();
        biz.setMerchantName("张三农资店");
        biz.setServicePhone("010-88886666");
        biz.setBizRegionCode("110105");
        biz.setBizRegionName("北京市/朝阳区");
        biz.setBizDetailAddress("某某路1号");
        dto.setBiz(biz);
        EntryApplyShopDTO shop = new EntryApplyShopDTO();
        shop.setShopName("张三旗舰店");
        shop.setShopPhone("13800138001");
        shop.setShopAvatar("/profile/shop/logo.jpg");
        dto.setShop(shop);
        return dto;
    }

    private EntryApplySubmitDTO buildValidEnterpriseDto()
    {
        EntryApplySubmitDTO dto = new EntryApplySubmitDTO();
        dto.setAgreementAccepted(true);
        BizMerchant subject = new BizMerchant();
        subject.setMerchantType(MerchantConstants.TYPE_ENTERPRISE);
        subject.setCompanyName("测试企业");
        subject.setRegRegionCode("110105");
        subject.setRegRegionName("北京市/朝阳区");
        subject.setCompanyDetailAddress("注册地址1号");
        subject.setBusinessScope("农资销售");
        subject.setCreditCode("91110000MA001");
        subject.setLicenseValidType(MerchantConstants.VALID_PERIOD_LONG);
        subject.setLegalName("李四");
        subject.setLegalResidence("北京市海淀区");
        subject.setLegalGender("0");
        subject.setLegalBirthDate(new Date());
        subject.setLegalIdCardType(MerchantConstants.ID_TYPE_MAINLAND);
        subject.setLegalIdCardNo("110101199001011235");
        subject.setLegalIdValidType(MerchantConstants.VALID_PERIOD_LONG);
        subject.setLegalIdCardFront("/profile/legal/front.jpg");
        subject.setLegalIdCardBack("/profile/legal/back.jpg");
        subject.setContactName("李四");
        subject.setContactPhone("13900139000");
        subject.setContactEmail("li@test.com");
        subject.setBankName("建设银行");
        subject.setBankBranch("海淀支行");
        subject.setBankAccount("6227000000000000");
        subject.setCorpBankAccount("1100000000000000");
        subject.setAccountPermit("/profile/permit.jpg");
        dto.setSubject(subject);
        BizMerchant biz = new BizMerchant();
        biz.setBizRegionCode("110105");
        biz.setBizRegionName("北京市/朝阳区");
        biz.setBizDetailAddress("经营地址1号");
        biz.setBusinessLicense("/profile/license.jpg");
        dto.setBiz(biz);
        EntryApplyShopDTO shop = new EntryApplyShopDTO();
        shop.setShopName("测试旗舰店");
        shop.setShopPhone("13900139001");
        shop.setShopAvatar("/profile/shop/logo2.jpg");
        dto.setShop(shop);
        return dto;
    }

    private BizMerchantEntryApply pendingApply()
    {
        BizMerchantEntryApply apply = new BizMerchantEntryApply();
        apply.setApplyId(1L);
        apply.setApplyNo("EA20260101001");
        apply.setApplyStatus(MerchantEntryApplyConstants.STATUS_PENDING);
        apply.setMerchantType(MerchantConstants.TYPE_PERSON);
        apply.setMemberId(100L);
        apply.setFormJson("{\"subject\":{\"merchantType\":\"1\",\"personName\":\"张三\",\"idCardNo\":\"110101199001011234\"},"
                + "\"biz\":{\"merchantName\":\"张三农资店\",\"contactName\":\"张三\",\"contactPhone\":\"13800138000\"},"
                + "\"shop\":{\"shopName\":\"张三旗舰店\"},\"agreementAccepted\":true}");
        return apply;
    }
}
