package com.ruoyi.app.mendian;

import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.system.domain.PosFood;
import com.ruoyi.system.service.IFoodSpecRelationService;
import com.ruoyi.system.service.IFoodSpecsService;
import com.ruoyi.system.service.IFoodSpecsValueService;
import com.ruoyi.system.service.IPosFoodService;
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.MockedStatic;
import org.springframework.test.util.ReflectionTestUtils;

import static org.junit.jupiter.api.Assertions.assertEquals;
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.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class PosFoodControllerAccessTest {

    private PosFoodController controller;
    private IPosFoodService posFoodService;
    private MerchantStoreAccessService accessService;
    private MockedStatic<MessageUtils> messages;
    private MockedStatic<AuthContext> authContext;

    @BeforeEach
    void setUp() {
        messages = mockStatic(MessageUtils.class);
        messages.when(() -> MessageUtils.message(org.mockito.ArgumentMatchers.anyString()))
                .thenAnswer(invocation -> invocation.getArgument(0));
        authContext = mockStatic(AuthContext.class);
        authContext.when(AuthContext::requireUserId).thenReturn(5L);
        controller = new PosFoodController();
        posFoodService = mock(IPosFoodService.class);
        accessService = mock(MerchantStoreAccessService.class);
        ReflectionTestUtils.setField(controller, "posFoodService", posFoodService);
        ReflectionTestUtils.setField(controller, "merchantStoreAccessService", accessService);
        ReflectionTestUtils.setField(controller, "foodSpecsService", mock(IFoodSpecsService.class));
        ReflectionTestUtils.setField(controller, "foodSpecsValueService", mock(IFoodSpecsValueService.class));
        ReflectionTestUtils.setField(controller, "foodSpecRelationService", mock(IFoodSpecRelationService.class));
        when(posFoodService.saveOrUpdate(any(PosFood.class))).thenReturn(true);
    }

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

    @Test
    void updateUsesPersistedFoodStoreInsteadOfSpoofedStore() {
        PosFood persisted = new PosFood();
        persisted.setId(20L);
        persisted.setMdid(10L);
        when(accessService.requireFoodAccess(5L, 20L)).thenReturn(persisted);
        PosFood request = new PosFood();
        request.setId(20L);
        request.setMdid(999L);

        controller.setposfood("token", request);

        ArgumentCaptor<PosFood> captor = ArgumentCaptor.forClass(PosFood.class);
        verify(posFoodService).saveOrUpdate(captor.capture());
        assertEquals(10L, captor.getValue().getMdid());
    }

    @Test
    void newFoodCannotUseUnauthorizedStore() {
        PosFood request = new PosFood();
        request.setMdid(999L);
        org.mockito.Mockito.doThrow(new ServiceException("denied"))
                .when(accessService).requireStoreAccess(5L, 999L);

        assertThrows(ServiceException.class, () -> controller.setposfood("token", request));
    }
}
