package tech.easyflow.chatlog.service.impl;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import tech.easyflow.chatlog.domain.dto.ChatSessionSummary;
import tech.easyflow.chatlog.service.ChatPersistDispatcher;
import tech.easyflow.chatlog.service.ChatSessionExtensionDispatcher;
import tech.easyflow.chatlog.service.ChatSessionQueryService;

import java.math.BigInteger;

/**
 * {@link ChatSessionCommandServiceImpl} 删除扩展顺序与失败传播测试。
 */
public class ChatSessionCommandServiceImplTest {

    /**
     * 验证所有删除入口共享 before、删除、after 的固定顺序。
     */
    @Test
    public void deleteShouldInvokeLifecycleHooksAroundPersistDispatch() {
        Fixture fixture = fixture();

        fixture.service.deleteSession(BigInteger.ONE, BigInteger.TWO, BigInteger.TWO);

        InOrder order = Mockito.inOrder(fixture.extensions, fixture.persistDispatcher);
        order.verify(fixture.extensions).beforeDelete(fixture.summary, BigInteger.TWO, BigInteger.TWO);
        order.verify(fixture.persistDispatcher).deleteSession(BigInteger.ONE, BigInteger.TWO, BigInteger.TWO);
        order.verify(fixture.extensions).afterDelete(fixture.summary, BigInteger.TWO, BigInteger.TWO);
    }

    /**
     * 验证会话删除失败时不会提前执行 after hook 标记关联资源删除。
     */
    @Test
    public void deleteFailureShouldNotInvokeAfterHook() {
        Fixture fixture = fixture();
        Mockito.doThrow(new IllegalStateException("mq unavailable"))
                .when(fixture.persistDispatcher).deleteSession(Mockito.any(), Mockito.any(), Mockito.any());

        Assert.assertThrows(IllegalStateException.class,
                () -> fixture.service.deleteSession(BigInteger.ONE, BigInteger.TWO, BigInteger.TWO));

        Mockito.verify(fixture.extensions, Mockito.never())
                .afterDelete(Mockito.any(), Mockito.any(), Mockito.any());
    }

    private Fixture fixture() {
        ChatPersistDispatcher persistDispatcher = Mockito.mock(ChatPersistDispatcher.class);
        ChatSessionQueryService queryService = Mockito.mock(ChatSessionQueryService.class);
        ChatSessionExtensionDispatcher extensions = Mockito.mock(ChatSessionExtensionDispatcher.class);
        ChatSessionSummary summary = new ChatSessionSummary();
        summary.setId(BigInteger.ONE);
        Mockito.when(queryService.getSessionSummary(BigInteger.ONE)).thenReturn(summary);
        return new Fixture(persistDispatcher, extensions, summary,
                new ChatSessionCommandServiceImpl(persistDispatcher, queryService, extensions));
    }

    private record Fixture(ChatPersistDispatcher persistDispatcher,
                           ChatSessionExtensionDispatcher extensions,
                           ChatSessionSummary summary,
                           ChatSessionCommandServiceImpl service) {
    }
}
