package com.ruoyi.app.mendian;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.app.service.UserService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.framework.web.exception.GlobalExceptionHandler;
import com.ruoyi.system.domain.InfoUser;
import com.ruoyi.system.domain.PosStore;
import com.ruoyi.system.service.IPosStoreService;
import com.ruoyi.system.service.IInfoUserService;
import com.ruoyi.system.service.MerchantStoreAccessService;
import com.ruoyi.system.utils.AuthContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.MockitoAnnotations;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

class PosStoreControllerTest {

    @Mock
    private IPosStoreService posStoreService;

    @Mock
    private IInfoUserService infoUserService;

    @Mock
    private UserService userService;

    @Mock
    private MerchantStoreAccessService merchantStoreAccessService;

    @InjectMocks
    private PosStoreController controller;

    private AutoCloseable mocks;
    private MockedStatic<MessageUtils> messages;
    private MockedStatic<AuthContext> authContext;
    private MockMvc mockMvc;
    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        mocks = MockitoAnnotations.openMocks(this);
        messages = org.mockito.Mockito.mockStatic(MessageUtils.class);
        messages.when(() -> MessageUtils.message(anyString()))
                .thenAnswer(invocation -> invocation.getArgument(0));
        authContext = org.mockito.Mockito.mockStatic(AuthContext.class);
        authContext.when(AuthContext::requireUserId).thenReturn(101L);
        mockMvc = MockMvcBuilders.standaloneSetup(controller)
                .setControllerAdvice(new GlobalExceptionHandler())
                .build();
        objectMapper = new ObjectMapper();
        when(posStoreService.saveOrUpdate(any(PosStore.class))).thenReturn(true);
    }

    @AfterEach
    void tearDown() throws Exception {
        authContext.close();
        messages.close();
        mocks.close();
    }

    @Test
    void unauditedMerchantCannotCreateStore() throws Exception {
        when(userService.checkUserStatus(101L))
                .thenThrow(new ServiceException("账号状态未审核"));

        mockMvc.perform(post("/chanting/store/addmendian")
                        .header("token", "token")
                        .contentType(APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(newStore(101L))))
                .andExpect(jsonPath("$.code").value(500))
                .andExpect(jsonPath("$.msg").value("账号状态未审核"));
    }

    @Test
    void auditedMerchantCreatesStoreOwnedByAuthenticatedOwner() throws Exception {
        when(userService.checkUserStatus(101L)).thenReturn(auditedMerchant(101L));
        PosStore saved = newStore(101L);
        saved.setId(9);
        when(posStoreService.getOne(any())).thenReturn(saved);

        mockMvc.perform(post("/chanting/store/addmendian")
                        .header("token", "token")
                        .contentType(APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(newStore(999L))))
                .andExpect(jsonPath("$.code").value(200));

        ArgumentCaptor<PosStore> captor = ArgumentCaptor.forClass(PosStore.class);
        org.mockito.Mockito.verify(posStoreService).saveOrUpdate(captor.capture());
        assertEquals(101L, captor.getValue().getUserId());
    }

    @Test
    void editingExistingStoreDoesNotRequireMerchantAudit() throws Exception {
        when(userService.checkUserStatus(any()))
                .thenThrow(new ServiceException("账号状态未审核"));
        PosStore existing = newStore(101L);
        existing.setId(9);
        when(posStoreService.getById(9)).thenReturn(existing);

        mockMvc.perform(post("/chanting/store/addmendian")
                        .header("token", "token")
                        .contentType(APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(existing)))
                .andExpect(jsonPath("$.code").value(200));
    }

    private static PosStore newStore(Long userId) {
        PosStore store = new PosStore();
        store.setPosName("测试门店");
        store.setUserId(userId);
        return store;
    }

    private static InfoUser auditedMerchant(Long userId) {
        InfoUser user = new InfoUser();
        user.setUserId(userId);
        user.setUserType("1");
        user.setAuditStatus("1");
        return user;
    }
}
