package tech.easyflow.agent.runtime.media;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import tech.easyflow.agent.config.AgentMediaProperties;
import tech.easyflow.common.entity.LoginAccount;

import java.math.BigInteger;
import java.time.Instant;
import java.util.List;

/**
 * {@link AgentMediaService} 正式图片绑定测试。
 */
public class AgentMediaServiceTest {

    private AgentMediaObjectStorage objectStorage;
    private RedisAgentMediaUploadStore uploadStore;
    private AgentMediaService service;
    private LoginAccount account;
    private AgentMediaUploadRecord upload;

    /**
     * 初始化媒体服务测试依赖。
     */
    @Before
    public void setUp() {
        objectStorage = Mockito.mock(AgentMediaObjectStorage.class);
        uploadStore = Mockito.mock(RedisAgentMediaUploadStore.class);
        service = new AgentMediaService(Mockito.mock(AgentImageProcessor.class), objectStorage,
                uploadStore, new AgentMediaProperties());
        account = new LoginAccount();
        account.setTenantId(BigInteger.valueOf(2));
        account.setId(BigInteger.valueOf(7));
        upload = buildUpload();
        Mockito.doAnswer(invocation -> {
            upload.setFormalReference(invocation.getArgument(1));
            return null;
        }).when(uploadStore).markFormalBinding(Mockito.same(upload), Mockito.anyString());
    }

    /**
     * 验证重复绑定同一上传凭据时复用首次正式引用。
     */
    @Test
    public void bindFormalShouldReuseExistingBinding() {
        List<AgentBoundMedia> first = service.bindFormal(List.of(upload), "101", "201", account);
        List<AgentBoundMedia> second = service.bindFormal(List.of(upload), "101", "202", account);

        Assert.assertEquals("formal:101:201:0:png", first.get(0).reference());
        Assert.assertEquals(first.get(0).reference(), second.get(0).reference());
        Assert.assertEquals("/api/v1/agent/media/content?reference=formal:101:201:0:png",
                second.get(0).payload().get("previewUrl"));
        Mockito.verify(objectStorage, Mockito.times(1))
                .copy("temp/2/7/upload-1.png", "formal/2/7/101/201/0.png");
        Mockito.verify(uploadStore, Mockito.times(1))
                .markFormalBinding(upload, "formal:101:201:0:png");
        Mockito.verify(objectStorage, Mockito.never()).delete(Mockito.anyString());
        Mockito.verify(uploadStore, Mockito.never()).delete(Mockito.any());
    }

    /**
     * 验证已绑定图片不能被复用到其他正式会话。
     */
    @Test
    public void bindFormalShouldRejectAnotherSession() {
        upload.setFormalReference("formal:101:201:0:png");

        ResponseStatusException error = Assert.assertThrows(ResponseStatusException.class,
                () -> service.bindFormal(List.of(upload), "102", "202", account));

        Assert.assertEquals(HttpStatus.CONFLICT, error.getStatusCode());
        Mockito.verify(objectStorage, Mockito.never()).copy(Mockito.anyString(), Mockito.anyString());
    }

    /**
     * 构造一条有效的临时图片凭据。
     *
     * @return 临时图片凭据
     */
    private AgentMediaUploadRecord buildUpload() {
        AgentMediaUploadRecord record = new AgentMediaUploadRecord();
        record.setUploadId("upload-1");
        record.setTenantId("2");
        record.setUserId("7");
        record.setMode(AgentMediaService.MODE_FORMAL);
        record.setAgentId("9");
        record.setSessionId("101");
        record.setObjectKey("temp/2/7/upload-1.png");
        record.setOriginalName("sample.png");
        record.setMimeType("image/png");
        record.setExtension("png");
        record.setSize(128L);
        record.setWidth(32);
        record.setHeight(32);
        record.setExpiresAt(Instant.now().plusSeconds(3600));
        return record;
    }
}
