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.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.List;
import java.util.Map;
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.BannerConstants;
import com.ruoyi.web.modules.content.domain.BizHomeBanner;
import com.ruoyi.web.modules.content.dto.BannerSortDTO;
import com.ruoyi.web.modules.content.mapper.BizHomeBannerMapper;
import com.ruoyi.web.modules.content.service.impl.BannerServiceImpl;
import com.ruoyi.web.modules.content.vo.HomeBannerAppVO;

/**
 * Banner Service 单元测试（BAN-UT）
 */
@ExtendWith(MockitoExtension.class)
class BannerServiceImplTest
{
    @Mock
    private BizHomeBannerMapper bannerMapper;

    @InjectMocks
    private BannerServiceImpl bannerService;

    @Test
    void insert_duplicateName_rejected()
    {
        BizHomeBanner row = baseRow();
        when(bannerMapper.countByName(eq("春耕主推"), eq(null))).thenReturn(1);

        ServiceException ex = assertThrows(ServiceException.class, () -> bannerService.insertBanner(row));
        assertEquals("图片名称已存在", ex.getMessage());
    }

    @Test
    void insert_defaults_enableAndSort()
    {
        BizHomeBanner row = baseRow();
        row.setEnableFlag(null);
        row.setSortNo(null);
        when(bannerMapper.countByName(any(), eq(null))).thenReturn(0);
        when(bannerMapper.insert(any())).thenAnswer(inv -> {
            BizHomeBanner b = inv.getArgument(0);
            b.setBannerId(1L);
            return 1;
        });

        bannerService.insertBanner(row);

        assertEquals(BannerConstants.ENABLE_YES, row.getEnableFlag());
        assertEquals(0, row.getSortNo());
    }

    @Test
    void insert_emptyName_rejected()
    {
        BizHomeBanner row = baseRow();
        row.setBannerName("");

        assertThrows(ServiceException.class, () -> bannerService.insertBanner(row));
    }

    @Test
    void insert_emptyImage_rejected()
    {
        BizHomeBanner row = baseRow();
        row.setBannerImage("");

        assertThrows(ServiceException.class, () -> bannerService.insertBanner(row));
    }

    @Test
    void insert_invalidImageExt_rejected()
    {
        BizHomeBanner row = baseRow();
        row.setBannerImage("/profile/upload/a.gif");

        assertThrows(ServiceException.class, () -> bannerService.insertBanner(row));
    }

    @Test
    void insert_negativeSort_rejected()
    {
        BizHomeBanner row = baseRow();
        row.setSortNo(-1);

        assertThrows(ServiceException.class, () -> bannerService.insertBanner(row));
    }

    @Test
    void update_deleted_rejected()
    {
        BizHomeBanner row = baseRow();
        row.setBannerId(1L);
        when(bannerMapper.selectById(1L)).thenReturn(null);

        assertThrows(ServiceException.class, () -> bannerService.updateBanner(row));
    }

    @Test
    void updateSortNo_success()
    {
        BizHomeBanner existing = baseRow();
        existing.setBannerId(1L);
        when(bannerMapper.selectById(1L)).thenReturn(existing);
        when(bannerMapper.updateSortNo(1L, 99, "admin")).thenReturn(1);

        BannerSortDTO dto = new BannerSortDTO();
        dto.setBannerId(1L);
        dto.setSortNo(99);
        bannerService.updateSortNo(dto, "admin");

        verify(bannerMapper).updateSortNo(1L, 99, "admin");
    }

    @Test
    void delete_success()
    {
        BizHomeBanner row = baseRow();
        row.setBannerId(1L);
        when(bannerMapper.selectById(1L)).thenReturn(row);

        String msg = bannerService.deleteBannerByIds(new Long[] { 1L }, "admin");

        assertEquals("操作成功", msg);
        verify(bannerMapper).logicDeleteByIds(eq(Collections.singletonList(1L)), eq("admin"));
    }

    @Test
    void delete_skipMissingId()
    {
        when(bannerMapper.selectById(1L)).thenReturn(baseRow());
        when(bannerMapper.selectById(2L)).thenReturn(null);

        String msg = bannerService.deleteBannerByIds(new Long[] { 1L, 2L }, "admin");

        assertTrue(msg.contains("跳过"));
        verify(bannerMapper).logicDeleteByIds(eq(Collections.singletonList(1L)), eq("admin"));
    }

    @Test
    void delete_allMissing_throws()
    {
        when(bannerMapper.selectById(1L)).thenReturn(null);

        assertThrows(ServiceException.class, () -> bannerService.deleteBannerByIds(new Long[] { 1L }, "admin"));
        verify(bannerMapper, never()).logicDeleteByIds(any(), any());
    }

    @Test
    void listForApp_onlyEnabled()
    {
        BizHomeBanner enabled = baseRow();
        enabled.setBannerId(1L);
        enabled.setEnableFlag(BannerConstants.ENABLE_YES);
        when(bannerMapper.selectEnabledForApp(BannerConstants.APP_LIST_LIMIT))
                .thenReturn(Collections.singletonList(enabled));

        List<HomeBannerAppVO> list = bannerService.listBannersForApp();

        assertEquals(1, list.size());
        assertEquals(1L, list.get(0).getBannerId());
        assertFalse(list.isEmpty());
    }

    @Test
    void insert_returnsBannerId()
    {
        BizHomeBanner row = baseRow();
        when(bannerMapper.countByName(any(), eq(null))).thenReturn(0);
        when(bannerMapper.insert(any())).thenAnswer(inv -> {
            BizHomeBanner b = inv.getArgument(0);
            b.setBannerId(5L);
            return 1;
        });

        Map<String, Object> data = bannerService.insertBanner(row);

        assertEquals(5L, data.get("bannerId"));
    }

    private static BizHomeBanner baseRow()
    {
        BizHomeBanner row = new BizHomeBanner();
        row.setBannerName("春耕主推");
        row.setBannerImage("/profile/upload/2026/05/b1.jpg");
        row.setEnableFlag(BannerConstants.ENABLE_YES);
        row.setSortNo(0);
        return row;
    }
}
