package com.ruoyi.web.modules.store.support;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.BeforeEach;
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.springframework.test.util.ReflectionTestUtils;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.store.constant.ShopConstants;
import com.ruoyi.web.modules.store.domain.BizMerchantAccount;
import com.ruoyi.web.modules.store.domain.BizShop;
import com.ruoyi.web.modules.store.mapper.BizMerchantAccountMapper;
import com.ruoyi.web.modules.store.mapper.BizShopMapper;

@ExtendWith(MockitoExtension.class)
class SellerShopContextSupportTest
{
    private static final String SESSION_TOKEN = "session-token-abc";

    @Mock
    private BizMerchantAccountMapper merchantAccountMapper;

    @Mock
    private BizShopMapper shopMapper;

    @Mock
    private RedisCache redisCache;

    @InjectMocks
    private SellerShopContextSupport support;

    @BeforeEach
    void setUp()
    {
        ReflectionTestUtils.setField(support, "tokenExpireMinutes", 30);
    }

    @Test
    void resolveDefaultShopId_employeeUsesBindingShop()
    {
        BizMerchantAccount account = new BizMerchantAccount();
        account.setMerchantId(1L);
        account.setShopId(101L);

        assertEquals(101L, support.resolveDefaultShopId(account));
    }

    @Test
    void resolveDefaultShopId_adminUsesEarliestShop()
    {
        BizMerchantAccount account = new BizMerchantAccount();
        account.setMerchantId(1L);
        BizShop shop = new BizShop();
        shop.setShopId(201L);
        when(shopMapper.selectEarliestByMerchantId(1L)).thenReturn(shop);

        assertEquals(201L, support.resolveDefaultShopId(account));
    }

    @Test
    void resolveCurrentShopId_prefersSavedSelection()
    {
        BizMerchantAccount account = new BizMerchantAccount();
        account.setMerchantId(1L);
        String key = ShopConstants.REDIS_SELLER_SHOP_CONTEXT_PREFIX + SESSION_TOKEN;
        when(redisCache.getCacheObject(key)).thenReturn(202L);
        when(shopMapper.countByShopIdAndMerchantId(202L, 1L)).thenReturn(1);

        assertEquals(202L, support.resolveCurrentShopId(SESSION_TOKEN, account));

        verify(redisCache).setCacheObject(eq(key), eq(202L), eq(30), eq(TimeUnit.MINUTES));
    }

    @Test
    void resolveCurrentShopId_fallsBackWhenSavedInvalid()
    {
        BizMerchantAccount account = new BizMerchantAccount();
        account.setMerchantId(1L);
        String key = ShopConstants.REDIS_SELLER_SHOP_CONTEXT_PREFIX + SESSION_TOKEN;
        when(redisCache.getCacheObject(key)).thenReturn(999L);
        when(shopMapper.countByShopIdAndMerchantId(999L, 1L)).thenReturn(0);
        BizShop shop = new BizShop();
        shop.setShopId(201L);
        when(shopMapper.selectEarliestByMerchantId(1L)).thenReturn(shop);

        assertEquals(201L, support.resolveCurrentShopId(SESSION_TOKEN, account));

        verify(redisCache).deleteObject(key);
    }

    @Test
    void saveSelectedShopId_writesRedisWithSessionTtl()
    {
        String key = ShopConstants.REDIS_SELLER_SHOP_CONTEXT_PREFIX + SESSION_TOKEN;

        support.saveSelectedShopId(SESSION_TOKEN, 202L);

        verify(redisCache).setCacheObject(key, 202L, 30, TimeUnit.MINUTES);
    }

    @Test
    void assertShopAccessible_rejectsEmployeeCrossShop()
    {
        BizMerchantAccount account = new BizMerchantAccount();
        account.setMerchantId(1L);
        account.setShopId(101L);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> support.assertShopAccessible(account, 102L));

        assertEquals(ShopConstants.MSG_SHOP_CONTEXT_INVALID, ex.getMessage());
    }
}
