package top.continew.admin.business.service.impl;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import top.continew.admin.business.mapper.DigitalHumanMapper;
import top.continew.admin.business.mapper.EffectMapper;
import top.continew.admin.business.mapper.SubtitleItemMapper;
import top.continew.admin.business.mapper.SubtitleStyleMapper;
import top.continew.admin.business.model.entity.DigitalHuman;
import top.continew.admin.business.model.entity.Effect;
import top.continew.admin.business.model.entity.SubtitleItem;
import top.continew.admin.business.model.entity.SubtitleStyle;
import top.continew.admin.business.model.req.DigitalHumanReq;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

/**
 * 数字人服务实现类单元测试
 *
 * @author 王志维
 * @since 2025/12/29
 */
class DigitalHumanServiceImplUnitTest {

    @Mock
    private DigitalHumanMapper digitalHumanMapper;

    @Mock
    private SubtitleStyleMapper subtitleStyleMapper;

    @Mock
    private SubtitleItemMapper subtitleItemMapper;

    @Mock
    private EffectMapper effectMapper;

    @InjectMocks
    private DigitalHumanServiceImpl digitalHumanService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    private DigitalHumanReq createDigitalHumanReq() {
        DigitalHumanReq req = new DigitalHumanReq();
        req.setUserId("1");
        req.setCopywriting("测试文案");
        req.setGeneratedVoiceUrl("http://test.com/voice.mp3");
        req.setGeneratedFrameImageUrl("http://test.com/frame.jpg");
        req.setGeneratedVideoUrl("http://test.com/video.mp4");

        // 添加字幕样式
        SubtitleStyle subtitleStyle = new SubtitleStyle();
        subtitleStyle.setFontSize(16);
        subtitleStyle.setColor("#FFFFFF");
        subtitleStyle.setStrokeColor("#000000");
        subtitleStyle.setStrokeWidth(2);
        req.setSubtitleStyle(subtitleStyle);

        // 添加字幕项
        SubtitleItem subtitleItem1 = new SubtitleItem();
        subtitleItem1.setStartTime(0.0);
        subtitleItem1.setEndTime(1.0);
        subtitleItem1.setText("测试字幕1");

        SubtitleItem subtitleItem2 = new SubtitleItem();
        subtitleItem2.setStartTime(1.0);
        subtitleItem2.setEndTime(2.0);
        subtitleItem2.setText("测试字幕2");

        // 添加特效
        Effect effect1 = new Effect();
        effect1.setType("text");
        effect1.setName("测试特效1");
        effect1.setSourceUrl("http://test.com/effect1.mp4");
        effect1.setLength(5.0);

        Effect effect2 = new Effect();
        effect2.setType("image");
        effect2.setName("测试特效2");
        effect2.setSourceUrl("http://test.com/effect2.jpg");
        effect2.setLength(3.0);

        return req;
    }

    @Test
    void testAdd() {
        // 准备测试数据
        DigitalHumanReq req = createDigitalHumanReq();

        // 模拟mapper行为，设置id
        when(digitalHumanMapper.insert(any(DigitalHuman.class))).thenAnswer(invocation -> {
            DigitalHuman digitalHuman = invocation.getArgument(0);
            digitalHuman.setId(1L); // 手动设置id
            return 1;
        });

        // 执行测试
        Long id = digitalHumanService.add(req);

        // 验证结果
        assertNotNull(id);

        // 验证调用次数
        verify(digitalHumanMapper, times(1)).insert(any(DigitalHuman.class));
        verify(subtitleStyleMapper, times(1)).insert(any(SubtitleStyle.class));
        verify(subtitleItemMapper, times(2)).insert(any(SubtitleItem.class));
        verify(effectMapper, times(2)).insert(any(Effect.class));
    }

    @Test
    void testUpdate() {
        // 准备测试数据
        DigitalHumanReq req = createDigitalHumanReq();
        Long id = 1L;

        // 模拟现有字幕样式
        SubtitleStyle existingStyle = new SubtitleStyle();
        existingStyle.setId(100L);
        existingStyle.setDigitalHumanId(id);
        List<SubtitleStyle> existingStyles = new ArrayList<>();
        existingStyles.add(existingStyle);
        when(subtitleStyleMapper.selectList(any())).thenReturn(existingStyles);

        // 执行测试
        digitalHumanService.update(req, id);

        // 验证调用次数
        verify(digitalHumanMapper, times(1)).updateById(any(DigitalHuman.class));
        verify(subtitleStyleMapper, times(1)).selectList(any());
        verify(subtitleStyleMapper, times(1)).updateById(any(SubtitleStyle.class));
        verify(subtitleItemMapper, times(1)).delete(any());
        verify(subtitleItemMapper, times(2)).insert(any(SubtitleItem.class));
        verify(effectMapper, times(1)).delete(any());
        verify(effectMapper, times(2)).insert(any(Effect.class));
    }

    @Test
    void testUpdateWithNewSubtitleStyle() {
        // 准备测试数据
        DigitalHumanReq req = createDigitalHumanReq();
        Long id = 1L;

        // 模拟没有现有字幕样式
        when(subtitleStyleMapper.selectList(any())).thenReturn(new ArrayList<>());

        // 执行测试
        digitalHumanService.update(req, id);

        // 验证调用次数
        verify(digitalHumanMapper, times(1)).updateById(any(DigitalHuman.class));
        verify(subtitleStyleMapper, times(1)).selectList(any());
        verify(subtitleStyleMapper, times(1)).insert(any(SubtitleStyle.class)); // 应该调用insert而不是update
        verify(subtitleItemMapper, times(1)).delete(any());
        verify(subtitleItemMapper, times(2)).insert(any(SubtitleItem.class));
        verify(effectMapper, times(1)).delete(any());
        verify(effectMapper, times(2)).insert(any(Effect.class));
    }

    @Test
    void testDelete() {
        // 准备测试数据
        Long id = 1L;
        List<Long> ids = List.of(id);

        // 执行测试
        digitalHumanService.delete(ids);

        // 验证调用次数
        verify(effectMapper, times(1)).delete(any());
        verify(subtitleItemMapper, times(1)).delete(any());
        verify(subtitleStyleMapper, times(1)).delete(any());
        verify(digitalHumanMapper, times(1)).deleteBatchIds(ids);
    }
}
