package com.ylx.massage.service.impl;

import com.ylx.common.exception.ServiceException;
import com.ylx.massage.domain.MaTechnician;
import com.ylx.massage.domain.dto.MaTechnicianStatusChangeDTO;
import com.ylx.massage.mapper.MaTechnicianMapper;
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.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 MaTechnicianServiceImplTest {

    @Test
    public void changeMerchantStatusUpdatesMerchantStatusAndReason() {
        MaTechnicianMapper mapper = mock(MaTechnicianMapper.class);
        MaTechnician existsMerchant = buildMerchant(9, 0);
        when(mapper.selectMerchantById(9)).thenReturn(existsMerchant);
        when(mapper.updateMerchantStatusById(any(MaTechnician.class))).thenReturn(1);
        MaTechnicianServiceImpl service = buildService(mapper);
        MaTechnicianStatusChangeDTO dto = buildDto(2, "risk review");

        int rows = service.changeMerchantStatus(9, dto, null);

        assertEquals(1, rows);
        ArgumentCaptor<MaTechnician> captor = ArgumentCaptor.forClass(MaTechnician.class);
        verify(mapper).updateMerchantStatusById(captor.capture());
        MaTechnician update = captor.getValue();
        assertEquals(9, update.getId());
        assertEquals(2, update.getMerchantStatus());
        assertEquals("risk review", update.getReasonChange());
        assertNotNull(update.getUpdateTime());
    }

    @Test
    public void changeMerchantStatusRejectsInvalidStatus() {
        MaTechnicianMapper mapper = mock(MaTechnicianMapper.class);
        MaTechnicianServiceImpl service = buildService(mapper);
        MaTechnicianStatusChangeDTO dto = buildDto(4, "bad status");

        assertThrows(ServiceException.class, () -> service.changeMerchantStatus(9, dto, null));

        verify(mapper, never()).selectMerchantById(any(Integer.class));
        verify(mapper, never()).updateMerchantStatusById(any(MaTechnician.class));
    }

    @Test
    public void changeMerchantStatusRejectsEmptyReason() {
        MaTechnicianMapper mapper = mock(MaTechnicianMapper.class);
        MaTechnicianServiceImpl service = buildService(mapper);
        MaTechnicianStatusChangeDTO dto = buildDto(1, " ");

        assertThrows(ServiceException.class, () -> service.changeMerchantStatus(9, dto, null));

        verify(mapper, never()).selectMerchantById(any(Integer.class));
        verify(mapper, never()).updateMerchantStatusById(any(MaTechnician.class));
    }

    @Test
    public void changeMerchantStatusRejectsMissingMerchant() {
        MaTechnicianMapper mapper = mock(MaTechnicianMapper.class);
        when(mapper.selectMerchantById(9)).thenReturn(null);
        MaTechnicianServiceImpl service = buildService(mapper);
        MaTechnicianStatusChangeDTO dto = buildDto(1, "limit order");

        assertThrows(ServiceException.class, () -> service.changeMerchantStatus(9, dto, null));

        verify(mapper, never()).updateMerchantStatusById(any(MaTechnician.class));
    }

    @Test
    public void changeMerchantStatusRejectsDeletedMerchant() {
        MaTechnicianMapper mapper = mock(MaTechnicianMapper.class);
        when(mapper.selectMerchantById(9)).thenReturn(buildMerchant(9, 1));
        MaTechnicianServiceImpl service = buildService(mapper);
        MaTechnicianStatusChangeDTO dto = buildDto(1, "limit order");

        assertThrows(ServiceException.class, () -> service.changeMerchantStatus(9, dto, null));

        verify(mapper, never()).updateMerchantStatusById(any(MaTechnician.class));
    }

    private MaTechnicianServiceImpl buildService(MaTechnicianMapper mapper) {
        MaTechnicianServiceImpl service = new MaTechnicianServiceImpl();
        ReflectionTestUtils.setField(service, "maTechnicianMapper", mapper);
        return service;
    }

    private MaTechnicianStatusChangeDTO buildDto(Integer merchantStatus, String reasonChange) {
        MaTechnicianStatusChangeDTO dto = new MaTechnicianStatusChangeDTO();
        dto.setMerchantStatus(merchantStatus);
        dto.setReasonChange(reasonChange);
        return dto;
    }

    private MaTechnician buildMerchant(Integer id, Integer isDelete) {
        MaTechnician merchant = new MaTechnician();
        merchant.setId(id);
        merchant.setIsDelete(isDelete);
        return merchant;
    }
}
