package com.ruoyi.asset.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.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.ruoyi.asset.constant.RfidBindStatus;
import com.ruoyi.asset.constant.RfidTagStatus;
import com.ruoyi.asset.domain.AmsRfidTag;
import com.ruoyi.asset.domain.RfidBindingContext;
import com.ruoyi.asset.mapper.AmsRfidTagMapper;
import com.ruoyi.asset.service.IAssetLifecycleService;
import com.ruoyi.asset.service.IRfidBindingService;
import com.ruoyi.common.exception.ServiceException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class AmsRfidTagServiceImplTest
{
    @Mock
    private AmsRfidTagMapper amsRfidTagMapper;

    @Mock
    private IAssetLifecycleService assetLifecycleService;

    @Mock
    private IRfidBindingService rfidBindingService;

    @InjectMocks
    private AmsRfidTagServiceImpl service;

    /** 现有Web解绑入口应委托公共绑定服务 */
    @Test
    void unbindShouldDelegateToRfidBindingService()
    {
        service.unbindAmsRfidTagByTagId(10L, 1L, "管理员", "admin");

        ArgumentCaptor<RfidBindingContext> contextCaptor = ArgumentCaptor.forClass(RfidBindingContext.class);
        verify(rfidBindingService).unbind(org.mockito.ArgumentMatchers.eq(10L), contextCaptor.capture());
        assertEquals(1L, contextCaptor.getValue().getOperateUserId());
        assertEquals("管理员", contextCaptor.getValue().getOperateUserName());
        assertEquals("admin", contextCaptor.getValue().getOperateLoginName());
    }

    /** 曾产生RFID履历的标签即使未绑定也禁止删除 */
    @Test
    void deleteShouldRejectTagWithRfidLifecycle()
    {
        AmsRfidTag tag = buildUnboundTag();
        when(amsRfidTagMapper.selectAmsRfidTagByTagIdForUpdate(10L)).thenReturn(tag);
        when(assetLifecycleService.hasRfidLifecycle(10L)).thenReturn(true);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.deleteAmsRfidTagByTagId(10L));

        assertTrue(exception.getMessage().contains("绑定履历"));
        verify(amsRfidTagMapper, never()).deleteAmsRfidTagByTagId(any());
    }

    /** 无当前绑定和RFID履历的标签允许删除 */
    @Test
    void deleteShouldLockAndDeleteUnusedTag()
    {
        AmsRfidTag tag = buildUnboundTag();
        when(amsRfidTagMapper.selectAmsRfidTagByTagIdForUpdate(10L)).thenReturn(tag);
        when(assetLifecycleService.hasRfidLifecycle(10L)).thenReturn(false);
        when(amsRfidTagMapper.deleteAmsRfidTagByTagId(10L)).thenReturn(1);

        assertEquals(1, service.deleteAmsRfidTagByTagId(10L));

        verify(amsRfidTagMapper).selectAmsRfidTagByTagIdForUpdate(10L);
    }

    /** 标签修改应先锁定记录并保留当前绑定状态 */
    @Test
    void updateShouldLockTagAndPreserveControlledFields()
    {
        AmsRfidTag current = buildUnboundTag();
        current.setTagStatus(RfidTagStatus.VOID);
        AmsRfidTag incoming = buildUnboundTag();
        incoming.setTagStatus(RfidTagStatus.NORMAL);
        incoming.setBindStatus(RfidBindStatus.BOUND);
        incoming.setAssetId(1L);
        when(amsRfidTagMapper.selectAmsRfidTagByTagIdForUpdate(10L)).thenReturn(current);
        when(amsRfidTagMapper.updateAmsRfidTag(any(AmsRfidTag.class))).thenReturn(1);

        service.updateAmsRfidTag(incoming);

        ArgumentCaptor<AmsRfidTag> tagCaptor = ArgumentCaptor.forClass(AmsRfidTag.class);
        verify(amsRfidTagMapper).updateAmsRfidTag(tagCaptor.capture());
        assertEquals(RfidTagStatus.VOID, tagCaptor.getValue().getTagStatus());
        assertEquals(RfidBindStatus.UNBOUND, tagCaptor.getValue().getBindStatus());
        assertNull(tagCaptor.getValue().getAssetId());
    }

    /** 已绑定标签在锁定检查后不能作废 */
    @Test
    void voidShouldRejectBoundTag()
    {
        AmsRfidTag tag = buildUnboundTag();
        tag.setBindStatus(RfidBindStatus.BOUND);
        tag.setAssetId(1L);
        when(amsRfidTagMapper.selectAmsRfidTagByTagIdForUpdate(10L)).thenReturn(tag);

        assertThrows(ServiceException.class, () -> service.voidAmsRfidTagByTagId(10L, "admin"));

        verify(amsRfidTagMapper, never()).voidAmsRfidTagByTagId(any(), any(), any());
    }

    private AmsRfidTag buildUnboundTag()
    {
        AmsRfidTag tag = new AmsRfidTag();
        tag.setTagId(10L);
        tag.setTagCode("TAG-001");
        tag.setEpcCode("EPC-001");
        tag.setTagStatus(RfidTagStatus.NORMAL);
        tag.setBindStatus(RfidBindStatus.UNBOUND);
        return tag;
    }
}
