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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
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.web.modules.content.constant.MallServiceAgreementConstants;
import com.ruoyi.web.modules.content.domain.BizMallServiceAgreement;
import com.ruoyi.web.modules.content.mapper.BizMallServiceAgreementMapper;
import com.ruoyi.web.modules.content.service.impl.MallServiceAgreementServiceImpl;
import com.ruoyi.web.modules.content.vo.MallServiceAgreementAppVO;
import com.ruoyi.web.modules.content.vo.MallServiceAgreementConfigVO;

/**
 * 商城服务协议 Service 单元测试（MSA-UT）
 */
@ExtendWith(MockitoExtension.class)
class MallServiceAgreementServiceImplTest
{
    @Mock
    private BizMallServiceAgreementMapper agreementMapper;

    @InjectMocks
    private MallServiceAgreementServiceImpl agreementService;

    @Test
    void getConfig_noRow_returnsDefaultShell()
    {
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(null);

        MallServiceAgreementConfigVO vo = agreementService.getConfig();

        assertEquals(MallServiceAgreementConstants.CONFIG_ID, vo.getConfigId());
        assertEquals(MallServiceAgreementConstants.ENABLE_NO, vo.getEnableFlag());
    }

    @Test
    void save_emptyTitle_rejected()
    {
        BizMallServiceAgreement row = baseRow();
        row.setAgreementTitle("  ");

        ServiceException ex = assertThrows(ServiceException.class,
                () -> agreementService.saveConfig(row, "admin"));
        assertEquals(MallServiceAgreementConstants.MSG_TITLE_REQUIRED, ex.getMessage());
    }

    @Test
    void save_enabledWithoutContent_rejected()
    {
        BizMallServiceAgreement row = baseRow();
        row.setContent("");

        ServiceException ex = assertThrows(ServiceException.class,
                () -> agreementService.saveConfig(row, "admin"));
        assertEquals(MallServiceAgreementConstants.MSG_CONTENT_REQUIRED_WHEN_ENABLED, ex.getMessage());
    }

    @Test
    void save_disabledEmptyContent_ok()
    {
        BizMallServiceAgreement row = baseRow();
        row.setEnableFlag(MallServiceAgreementConstants.ENABLE_NO);
        row.setContent("");
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(null);
        when(agreementMapper.insert(any())).thenReturn(1);

        agreementService.saveConfig(row, "admin");

        verify(agreementMapper).insert(any());
    }

    @Test
    void getForApp_disabled_sp4Flags()
    {
        BizMallServiceAgreement row = baseRow();
        row.setEnableFlag(MallServiceAgreementConstants.ENABLE_NO);
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(row);

        MallServiceAgreementAppVO vo = agreementService.getForApp();

        assertFalse(vo.isEnabled());
        assertFalse(vo.isRegistrationOpen());
        assertFalse(vo.isRequireAgreementOnLogin());
        assertEquals(MallServiceAgreementConstants.MSG_REGISTRATION_CLOSED, vo.getMessage());
    }

    @Test
    void getForApp_enabled_withFlags()
    {
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(baseRow());

        MallServiceAgreementAppVO vo = agreementService.getForApp();

        assertTrue(vo.isEnabled());
        assertTrue(vo.isRegistrationOpen());
        assertTrue(vo.isRequireAgreementOnLogin());
    }

    @Test
    void assertAcceptedForRegister_notOpen_rejected()
    {
        BizMallServiceAgreement row = baseRow();
        row.setEnableFlag(MallServiceAgreementConstants.ENABLE_NO);
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(row);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> agreementService.assertAcceptedForRegister(true));
        assertEquals(MallServiceAgreementConstants.MSG_REGISTRATION_CLOSED, ex.getMessage());
    }

    @Test
    void assertAcceptedForRegister_notAccepted_rejected()
    {
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(baseRow());

        ServiceException ex = assertThrows(ServiceException.class,
                () -> agreementService.assertAcceptedForRegister(false));
        assertEquals(MallServiceAgreementConstants.MSG_AGREE_REQUIRED, ex.getMessage());
    }

    @Test
    void assertAcceptedForLogin_disabled_skipsCheck()
    {
        BizMallServiceAgreement row = baseRow();
        row.setEnableFlag(MallServiceAgreementConstants.ENABLE_NO);
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(row);

        agreementService.assertAcceptedForLogin(false);
    }

    @Test
    void assertAcceptedForLogin_enabled_notAccepted_rejected()
    {
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(baseRow());

        assertThrows(ServiceException.class, () -> agreementService.assertAcceptedForLogin(false));
    }

    @Test
    void assertAcceptedForLogin_enabled_accepted_ok()
    {
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(baseRow());

        agreementService.assertAcceptedForLogin(true);
    }

    @Test
    void save_existing_updates()
    {
        BizMallServiceAgreement row = baseRow();
        when(agreementMapper.selectById(MallServiceAgreementConstants.CONFIG_ID)).thenReturn(baseRow());
        when(agreementMapper.update(any())).thenReturn(1);

        agreementService.saveConfig(row, "admin");

        verify(agreementMapper).update(any());
        verify(agreementMapper, never()).insert(any());
    }

    private static BizMallServiceAgreement baseRow()
    {
        BizMallServiceAgreement row = new BizMallServiceAgreement();
        row.setConfigId(MallServiceAgreementConstants.CONFIG_ID);
        row.setAgreementTitle("农资商城用户服务协议");
        row.setVersionLabel("v1.0");
        row.setContent("<p>正文</p>");
        row.setEnableFlag(MallServiceAgreementConstants.ENABLE_YES);
        return row;
    }
}
