package com.ylx.massage.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.ylx.common.exception.ServiceException;
import com.ylx.massage.domain.MaTechnician;
import com.ylx.moment.domain.MomentMedia;
import com.ylx.moment.domain.TechnicianMoment;
import com.ylx.moment.domain.vo.MomentAuditStatusCountVO;
import com.ylx.massage.mapper.MaTechnicianMapper;
import com.ylx.moment.mapper.MomentMediaMapper;
import com.ylx.moment.mapper.TechnicianMomentMapper;
import com.ylx.moment.service.impl.TechnicianMomentServiceImpl;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.test.util.ReflectionTestUtils;

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.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class TechnicianMomentServiceImplTest {

    @Test
    public void deleteMyMomentRejectsEmptyMomentId() {
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.deleteMyMoment(null, "openid"));

        assertEquals("动态ID不能为空", exception.getMessage());
    }

    @Test
    public void deleteMyMomentRejectsPendingMoment() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        MaTechnicianMapper technicianMapper = mock(MaTechnicianMapper.class);
        MomentMediaMapper mediaMapper = mock(MomentMediaMapper.class);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);
        ReflectionTestUtils.setField(service, "maTechnicianMapper", technicianMapper);
        ReflectionTestUtils.setField(service, "mediaMapper", mediaMapper);
        MaTechnician technician = buildTechnician(7);
        TechnicianMoment moment = buildMoment(10L, 7, 1, 0);
        when(technicianMapper.selectOne(any(Wrapper.class))).thenReturn(technician);
        when(mapper.selectById(10L)).thenReturn(moment);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.deleteMyMoment(10L, "openid"));

        assertEquals("审核中的动态不支持删除", exception.getMessage());
        verify(mapper, never()).update(any(TechnicianMoment.class), any(Wrapper.class));
        verify(mediaMapper, never()).update(any(MomentMedia.class), any(Wrapper.class));
    }

    @Test
    public void deleteMyMomentRejectsOtherTechnicianMoment() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        MaTechnicianMapper technicianMapper = mock(MaTechnicianMapper.class);
        MomentMediaMapper mediaMapper = mock(MomentMediaMapper.class);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);
        ReflectionTestUtils.setField(service, "maTechnicianMapper", technicianMapper);
        ReflectionTestUtils.setField(service, "mediaMapper", mediaMapper);
        MaTechnician technician = buildTechnician(7);
        TechnicianMoment moment = buildMoment(10L, 8, 2, 0);
        when(technicianMapper.selectOne(any(Wrapper.class))).thenReturn(technician);
        when(mapper.selectById(10L)).thenReturn(moment);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.deleteMyMoment(10L, "openid"));

        assertEquals("无权删除此动态", exception.getMessage());
        verify(mapper, never()).update(any(TechnicianMoment.class), any(Wrapper.class));
        verify(mediaMapper, never()).update(any(MomentMedia.class), any(Wrapper.class));
    }

    @Test
    public void deleteMyMomentLogicDeletesApprovedMomentAndMedia() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        MaTechnicianMapper technicianMapper = mock(MaTechnicianMapper.class);
        MomentMediaMapper mediaMapper = mock(MomentMediaMapper.class);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);
        ReflectionTestUtils.setField(service, "maTechnicianMapper", technicianMapper);
        ReflectionTestUtils.setField(service, "mediaMapper", mediaMapper);
        MaTechnician technician = buildTechnician(7);
        TechnicianMoment moment = buildMoment(10L, 7, 2, 0);
        when(technicianMapper.selectOne(any(Wrapper.class))).thenReturn(technician);
        when(mapper.selectById(10L)).thenReturn(moment);
        when(mapper.update(any(TechnicianMoment.class), any(Wrapper.class))).thenReturn(1);
        when(mediaMapper.update(any(MomentMedia.class), any(Wrapper.class))).thenReturn(2);

        Boolean result = service.deleteMyMoment(10L, "openid");

        assertTrue(result);
        ArgumentCaptor<TechnicianMoment> momentCaptor = ArgumentCaptor.forClass(TechnicianMoment.class);
        verify(mapper).update(momentCaptor.capture(), any(Wrapper.class));
        TechnicianMoment update = momentCaptor.getValue();
        assertEquals(1, update.getIsDelete());
        assertEquals("openid", update.getUpdateBy());
        assertNotNull(update.getUpdateTime());
        ArgumentCaptor<MomentMedia> mediaCaptor = ArgumentCaptor.forClass(MomentMedia.class);
        verify(mediaMapper).update(mediaCaptor.capture(), any(Wrapper.class));
        assertEquals(1, mediaCaptor.getValue().getIsDelete());
    }

    @Test
    public void updateRecommendStatusRejectsEmptyMomentId() {
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.updateRecommendStatus(null, 1));

        assertEquals("动态ID不能为空", exception.getMessage());
    }

    @Test
    public void updateRecommendStatusRejectsInvalidRecommendStatus() {
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.updateRecommendStatus(1L, 2));

        assertEquals("是否推荐参数不正确", exception.getMessage());
    }

    @Test
    public void updateRecommendStatusDelegatesToMapper() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        when(mapper.updateRecommendStatus(10L, 1)).thenReturn(1);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);

        Boolean result = service.updateRecommendStatus(10L, 1);

        assertTrue(result);
        verify(mapper).updateRecommendStatus(10L, 1);
    }

    @Test
    public void updateRecommendStatusRejectsMissingMoment() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        when(mapper.updateRecommendStatus(10L, 1)).thenReturn(0);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.updateRecommendStatus(10L, 1));

        assertEquals("动态不存在或已删除", exception.getMessage());
    }

    @Test
    public void updateListStatusRejectsEmptyMomentId() {
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.updateListStatus(null, 1));

        assertEquals("动态ID不能为空", exception.getMessage());
    }

    @Test
    public void updateListStatusRejectsInvalidListStatus() {
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.updateListStatus(1L, 2));

        assertEquals("上架状态参数不正确", exception.getMessage());
    }

    @Test
    public void updateListStatusDelegatesToMapper() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        when(mapper.updateListStatus(10L, 1)).thenReturn(1);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);

        Boolean result = service.updateListStatus(10L, 1);

        assertTrue(result);
        verify(mapper).updateListStatus(10L, 1);
    }

    @Test
    public void updateListStatusRejectsMissingMoment() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        when(mapper.updateListStatus(10L, 1)).thenReturn(0);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.updateListStatus(10L, 1));

        assertEquals("动态不存在或已删除", exception.getMessage());
    }

    @Test
    public void getManageAuditStatusCountDelegatesToMapper() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        MomentAuditStatusCountVO count = new MomentAuditStatusCountVO();
        count.setPendingCount(1L);
        count.setApprovedCount(2L);
        count.setRejectedCount(3L);
        when(mapper.selectManageAuditStatusCount()).thenReturn(count);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);

        MomentAuditStatusCountVO result = service.getManageAuditStatusCount();

        assertEquals(1L, result.getPendingCount());
        assertEquals(2L, result.getApprovedCount());
        assertEquals(3L, result.getRejectedCount());
        verify(mapper).selectManageAuditStatusCount();
    }

    @Test
    public void getManageAuditStatusCountReturnsZeroWhenMapperReturnsNull() {
        TechnicianMomentMapper mapper = mock(TechnicianMomentMapper.class);
        when(mapper.selectManageAuditStatusCount()).thenReturn(null);
        TechnicianMomentServiceImpl service = new TechnicianMomentServiceImpl();
        ReflectionTestUtils.setField(service, "momentMapper", mapper);

        MomentAuditStatusCountVO result = service.getManageAuditStatusCount();

        assertEquals(0L, result.getPendingCount());
        assertEquals(0L, result.getApprovedCount());
        assertEquals(0L, result.getRejectedCount());
    }

    private MaTechnician buildTechnician(Integer id) {
        MaTechnician technician = new MaTechnician();
        technician.setId(id);
        return technician;
    }

    private TechnicianMoment buildMoment(Long id, Integer technicianId, Integer auditStatus, Integer isDelete) {
        TechnicianMoment moment = new TechnicianMoment();
        moment.setId(id);
        moment.setTechnicianId(technicianId);
        moment.setAuditStatus(auditStatus);
        moment.setIsDelete(isDelete);
        return moment;
    }
}
