package com.dora.service;

import com.dora.dto.CourseUpdateDto;
import com.dora.entity.Course;
import com.dora.entity.CourseChapter;
import com.dora.entity.CourseVideo;
import com.dora.entity.Video;
import com.dora.entity.User;
import com.dora.exception.BusinessException;
import com.dora.mapper.CourseMapper;
import com.dora.mapper.CourseChapterMapper;
import com.dora.mapper.CourseVideoMapper;
import com.dora.mapper.VideoMapper;
import com.dora.mapper.UserMapper;
import com.dora.service.impl.CourseServiceImpl;
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 java.math.BigDecimal;
import java.util.Arrays;

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

@ExtendWith(MockitoExtension.class)
class CourseServiceUpdateTest {

    @Mock
    private CourseMapper courseMapper;

    @Mock
    private CourseChapterMapper courseChapterMapper;

    @Mock
    private CourseVideoMapper courseVideoMapper;

    @Mock
    private VideoMapper videoMapper;

    @Mock
    private UserMapper userMapper;

    @InjectMocks
    private CourseServiceImpl courseService;

    private Course testCourse;
    private CourseUpdateDto testUpdateDto;

    @BeforeEach
    void setUp() {
        // 设置测试课程
        testCourse = new Course();
        testCourse.setId(1L);
        testCourse.setUserId(100L);
        testCourse.setTitle("原课程标题");
        testCourse.setDescription("原课程描述");
        testCourse.setPrice(new BigDecimal("29.99"));
        testCourse.setLevel(1);
        testCourse.setCategory("AI");
        testCourse.setIsFree(0);

        // 设置测试更新DTO
        testUpdateDto = new CourseUpdateDto();
        testUpdateDto.setTitle("新课程标题");
        testUpdateDto.setDescription("新课程描述");
        testUpdateDto.setPrice(new BigDecimal("39.99"));
        testUpdateDto.setLevel(2);
        testUpdateDto.setCategory("机器学习");
        testUpdateDto.setIsFree(true);
        testUpdateDto.setDeleteMissing(true);

        // 设置章节更新
        CourseUpdateDto.ChapterUpdateDto chapterDto = new CourseUpdateDto.ChapterUpdateDto();
        chapterDto.setTitle("新章节");
        chapterDto.setDescription("新章节描述");
        chapterDto.setOrderNum(1);

        // 设置视频更新
        CourseUpdateDto.VideoUpdateDto videoDto = new CourseUpdateDto.VideoUpdateDto();
        videoDto.setTitle("新视频");
        videoDto.setOrderNum(1);
        videoDto.setDurationSec(120);
        videoDto.setVodVideoId("vod-test123");

        chapterDto.setVideos(Arrays.asList(videoDto));
        testUpdateDto.setChapters(Arrays.asList(chapterDto));
    }

    @Test
    void testUpdateCourse_Success() {
        // 模拟课程存在且用户有权限
        when(courseMapper.selectById(1L)).thenReturn(testCourse);
        when(courseMapper.updateById(any(Course.class))).thenReturn(1);
        when(courseMapper.submitForAudit(anyLong(), anyLong(), anyString(), anyString(), anyInt(), anyInt())).thenReturn(1);

        // 模拟用户信息
        User mockUser = new User();
        mockUser.setId(100L);
        mockUser.setUsername("测试用户");
        mockUser.setAvatarUrl("http://test.com/avatar.jpg");
        when(userMapper.selectById(100L)).thenReturn(mockUser);

        // 模拟章节创建
        CourseChapter newChapter = new CourseChapter();
        newChapter.setId(10L);
        when(courseChapterMapper.insert(any(CourseChapter.class))).thenReturn(1);

        // 模拟视频创建
        CourseVideo newVideo = new CourseVideo();
        newVideo.setId(20L);
        when(courseVideoMapper.insert(any(CourseVideo.class))).thenReturn(1);

        // 模拟Video记录创建
        Video newVideoEntity = new Video();
        newVideoEntity.setId(30L);
        when(videoMapper.selectByVodVideoId("vod-test123")).thenReturn(null);
        when(videoMapper.insert(any(Video.class))).thenReturn(1);

        // 模拟查询现有章节和视频（空列表，因为是新建）
        when(courseChapterMapper.selectByCourseId(1L)).thenReturn(Arrays.asList());
        when(courseVideoMapper.selectByChapterIds(anyList())).thenReturn(Arrays.asList());

        // 执行更新
        assertDoesNotThrow(() -> courseService.updateCourse(1L, 100L, testUpdateDto));

        // 验证调用
        verify(courseMapper).updateById(any(Course.class));
        verify(courseChapterMapper).insert(any(CourseChapter.class));
        verify(courseVideoMapper).insert(any(CourseVideo.class));
        verify(videoMapper).insert(any(Video.class));
        verify(courseMapper).submitForAudit(eq(1L), eq(100L), anyString(), anyString(), anyInt(), anyInt());
    }

    @Test
    void testUpdateCourse_CourseNotFound() {
        when(courseMapper.selectById(1L)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, 
            () -> courseService.updateCourse(1L, 100L, testUpdateDto));
        
        assertEquals("课程不存在", exception.getMessage());
    }

    @Test
    void testUpdateCourse_NoPermission() {
        testCourse.setUserId(200L); // 不同的用户ID
        when(courseMapper.selectById(1L)).thenReturn(testCourse);

        BusinessException exception = assertThrows(BusinessException.class, 
            () -> courseService.updateCourse(1L, 100L, testUpdateDto));
        
        assertEquals("无权限修改此课程", exception.getMessage());
    }

    @Test
    void testUpdateCourse_UpdateExistingChapter() {
        // 设置现有章节
        CourseChapter existingChapter = new CourseChapter();
        existingChapter.setId(10L);
        existingChapter.setCourseId(1L);

        // 设置更新DTO为更新现有章节
        CourseUpdateDto.ChapterUpdateDto chapterDto = new CourseUpdateDto.ChapterUpdateDto();
        chapterDto.setId(10L);
        chapterDto.setTitle("更新的章节标题");
        chapterDto.setOrderNum(1);
        testUpdateDto.setChapters(Arrays.asList(chapterDto));

        when(courseMapper.selectById(1L)).thenReturn(testCourse);
        when(courseMapper.updateById(any(Course.class))).thenReturn(1);
        when(courseChapterMapper.updateById(any(CourseChapter.class))).thenReturn(1);
        when(courseChapterMapper.selectByCourseId(1L)).thenReturn(Arrays.asList(existingChapter));
        when(courseVideoMapper.selectByChapterIds(anyList())).thenReturn(Arrays.asList());

        // 模拟用户信息
        User mockUser = new User();
        mockUser.setId(100L);
        mockUser.setUsername("测试用户");
        mockUser.setAvatarUrl("http://test.com/avatar.jpg");
        when(userMapper.selectById(100L)).thenReturn(mockUser);

        assertDoesNotThrow(() -> courseService.updateCourse(1L, 100L, testUpdateDto));

        verify(courseChapterMapper).updateById(any(CourseChapter.class));
        verify(courseChapterMapper, never()).insert(any(CourseChapter.class));
    }

    @Test
    void testUpdateCourse_UpdateExistingVideo() {
        // 设置现有章节和视频
        CourseChapter existingChapter = new CourseChapter();
        existingChapter.setId(10L);
        existingChapter.setCourseId(1L);

        CourseVideo existingVideo = new CourseVideo();
        existingVideo.setId(20L);
        existingVideo.setChapterId(10L);

        // 设置更新DTO为更新现有视频
        CourseUpdateDto.ChapterUpdateDto chapterDto = new CourseUpdateDto.ChapterUpdateDto();
        chapterDto.setId(10L);
        chapterDto.setTitle("章节标题");

        CourseUpdateDto.VideoUpdateDto videoDto = new CourseUpdateDto.VideoUpdateDto();
        videoDto.setId(20L);
        videoDto.setTitle("更新的视频标题");
        videoDto.setOrderNum(1);
        videoDto.setDurationSec(180);
        videoDto.setVideoId("30"); // 使用现有videoId，转换为String类型

        chapterDto.setVideos(Arrays.asList(videoDto));
        testUpdateDto.setChapters(Arrays.asList(chapterDto));

        when(courseMapper.selectById(1L)).thenReturn(testCourse);
        when(courseMapper.updateById(any(Course.class))).thenReturn(1);
        when(courseChapterMapper.updateById(any(CourseChapter.class))).thenReturn(1);
        when(courseVideoMapper.updateById(any(CourseVideo.class))).thenReturn(1);
        when(courseChapterMapper.selectByCourseId(1L)).thenReturn(Arrays.asList(existingChapter));
        when(courseVideoMapper.selectByChapterIds(anyList())).thenReturn(Arrays.asList(existingVideo));

        // 模拟用户信息
        User mockUser = new User();
        mockUser.setId(100L);
        mockUser.setUsername("测试用户");
        mockUser.setAvatarUrl("http://test.com/avatar.jpg");
        when(userMapper.selectById(100L)).thenReturn(mockUser);

        assertDoesNotThrow(() -> courseService.updateCourse(1L, 100L, testUpdateDto));

        verify(courseVideoMapper).updateById(any(CourseVideo.class));
        verify(courseVideoMapper, never()).insert(any(CourseVideo.class));
    }

    @Test
    void testUpdateCourse_InvalidVideoDto() {
        // 设置无效的视频DTO（既没有videoId也没有vodVideoId）
        CourseUpdateDto.ChapterUpdateDto chapterDto = new CourseUpdateDto.ChapterUpdateDto();
        chapterDto.setTitle("章节标题");

        CourseUpdateDto.VideoUpdateDto videoDto = new CourseUpdateDto.VideoUpdateDto();
        videoDto.setTitle("视频标题");
        // 故意不设置videoId和vodVideoId

        chapterDto.setVideos(Arrays.asList(videoDto));
        testUpdateDto.setChapters(Arrays.asList(chapterDto));

        when(courseMapper.selectById(1L)).thenReturn(testCourse);

        BusinessException exception = assertThrows(BusinessException.class, 
            () -> courseService.updateCourse(1L, 100L, testUpdateDto));
        
        assertEquals("视频必须提供videoId或vodVideoId", exception.getMessage());
    }

    @Test
    void testUpdateCourse_DeleteMissingChapters() {
        // 设置现有章节
        CourseChapter existingChapter = new CourseChapter();
        existingChapter.setId(10L);
        existingChapter.setCourseId(1L);

        // 更新DTO不包含现有章节，应该被删除
        testUpdateDto.setChapters(Arrays.asList()); // 空章节列表
        testUpdateDto.setDeleteMissing(true);

        when(courseMapper.selectById(1L)).thenReturn(testCourse);
        when(courseMapper.updateById(any(Course.class))).thenReturn(1);
        when(courseChapterMapper.selectByCourseId(1L)).thenReturn(Arrays.asList(existingChapter));
        when(courseVideoMapper.selectByChapterIds(anyList())).thenReturn(Arrays.asList());
        when(courseChapterMapper.softDelete(anyLong(), anyLong())).thenReturn(1);

        // 模拟用户信息
        User mockUser = new User();
        mockUser.setId(100L);
        mockUser.setUsername("测试用户");
        mockUser.setAvatarUrl("http://test.com/avatar.jpg");
        when(userMapper.selectById(100L)).thenReturn(mockUser);

        assertDoesNotThrow(() -> courseService.updateCourse(1L, 100L, testUpdateDto));

        verify(courseChapterMapper).softDelete(10L, 1L);
    }
} 