package com.ruoyi.web.modules.diagnosis.service.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
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.argThat;
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.Arrays;
import java.util.Collections;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.diagnosis.OrgMyAppointmentTestSamples;
import com.ruoyi.web.modules.diagnosis.domain.BizServiceAppointment;
import com.ruoyi.web.modules.diagnosis.mapper.BizServiceAppointmentMapper;
import com.ruoyi.web.modules.diagnosis.support.OrgProviderResolver;
import com.ruoyi.web.modules.diagnosis.support.ServiceAppointmentRules;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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 org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@DisplayName("BizOrgMyAppointmentServiceImpl")
class BizOrgMyAppointmentServiceImplTest
{
    @Mock
    private BizServiceAppointmentMapper appointmentMapper;

    @Mock
    private OrgProviderResolver orgProviderResolver;

    @InjectMocks
    private BizOrgMyAppointmentServiceImpl service;

    @BeforeEach
    void bindProvider()
    {
        when(orgProviderResolver.resolveProviderId(OrgMyAppointmentTestSamples.SYS_USER_ID))
                .thenReturn(OrgMyAppointmentTestSamples.ORG_PROVIDER_ID);
    }

    @Test
    @DisplayName("未绑定返回空列表")
    void listUnbound()
    {
        when(orgProviderResolver.resolveProviderId(99L)).thenReturn(null);
        assertTrue(service.selectOrgAppointmentList(new BizServiceAppointment(), 99L).isEmpty());
        verify(appointmentMapper, never()).selectOrgAppointmentList(any());
    }

    @Test
    @DisplayName("列表 scope")
    void listScope()
    {
        when(appointmentMapper.selectOrgAppointmentList(any()))
                .thenReturn(Collections.singletonList(OrgMyAppointmentTestSamples.bookedAppointment()));
        service.selectOrgAppointmentList(new BizServiceAppointment(), OrgMyAppointmentTestSamples.SYS_USER_ID);
        verify(appointmentMapper).selectOrgAppointmentList(argThat(q ->
                ServiceAppointmentRules.PROVIDER_TYPE_ORG == q.getProviderType()
                        && OrgMyAppointmentTestSamples.ORG_PROVIDER_ID.equals(q.getProviderId())));
    }

    @Test
    @DisplayName("列表过滤串单状态")
    void listFilterAnomaly()
    {
        when(appointmentMapper.selectOrgAppointmentList(any()))
                .thenReturn(Arrays.asList(
                        OrgMyAppointmentTestSamples.bookedAppointment(),
                        OrgMyAppointmentTestSamples.anomalyPendingAppointment()));
        assertEquals(1, service.selectOrgAppointmentList(new BizServiceAppointment(),
                OrgMyAppointmentTestSamples.SYS_USER_ID).size());
    }

    @Test
    @DisplayName("详情成功并脱敏")
    void detail()
    {
        BizServiceAppointment booked = OrgMyAppointmentTestSamples.bookedAppointment();
        booked.setRejectReason("不应展示");
        when(appointmentMapper.selectOrgAppointmentByIdAndProvider(2000L, OrgMyAppointmentTestSamples.ORG_PROVIDER_ID))
                .thenReturn(booked);
        BizServiceAppointment result = service.selectOrgAppointmentById(2000L, OrgMyAppointmentTestSamples.SYS_USER_ID);
        assertEquals("已预约", result.getStatusLabel());
        assertNull(result.getRejectReason());
        assertNull(result.getConfirmTime());
        assertNull(result.getRejectTime());
    }

    @Test
    @DisplayName("越权记录")
    void notOwned()
    {
        when(appointmentMapper.selectOrgAppointmentByIdAndProvider(eq(9999L), any())).thenReturn(null);
        assertThrows(ServiceException.class,
                () -> service.selectOrgAppointmentById(9999L, OrgMyAppointmentTestSamples.SYS_USER_ID));
    }

    @Test
    @DisplayName("未绑定无法查详情")
    void unboundDetail()
    {
        when(orgProviderResolver.resolveProviderId(99L)).thenReturn(null);
        ServiceException ex = assertThrows(ServiceException.class,
                () -> service.selectOrgAppointmentById(1L, 99L));
        assertTrue(ex.getMessage().contains("未绑定机构资源"));
    }

    @Test
    @DisplayName("已预约可完成接诊")
    void completeBooked()
    {
        when(appointmentMapper.selectOrgAppointmentByIdAndProvider(2000L, OrgMyAppointmentTestSamples.ORG_PROVIDER_ID))
                .thenReturn(OrgMyAppointmentTestSamples.bookedAppointment());
        when(appointmentMapper.updateCompleteOrgAppointment(any())).thenReturn(1);
        assertEquals(1, service.complete(2000L, OrgMyAppointmentTestSamples.SYS_USER_ID, "orgA"));
    }

    @Test
    @DisplayName("已取消不可完成接诊")
    void completeCancelledBlocked()
    {
        when(appointmentMapper.selectOrgAppointmentByIdAndProvider(2001L, OrgMyAppointmentTestSamples.ORG_PROVIDER_ID))
                .thenReturn(OrgMyAppointmentTestSamples.cancelledAppointment());
        assertThrows(ServiceException.class,
                () -> service.complete(2001L, OrgMyAppointmentTestSamples.SYS_USER_ID, "orgA"));
    }

    @Test
    @DisplayName("串单状态详情异常")
    void anomalyDetail()
    {
        when(appointmentMapper.selectOrgAppointmentByIdAndProvider(2099L, OrgMyAppointmentTestSamples.ORG_PROVIDER_ID))
                .thenReturn(OrgMyAppointmentTestSamples.anomalyPendingAppointment());
        ServiceException ex = assertThrows(ServiceException.class,
                () -> service.selectOrgAppointmentById(2099L, OrgMyAppointmentTestSamples.SYS_USER_ID));
        assertTrue(ex.getMessage().contains("状态异常"));
    }
}
