package com.mosquito.project.service;

import com.mosquito.project.persistence.entity.ShortLinkEntity;
import com.mosquito.project.persistence.repository.ShortLinkRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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 java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@DisplayName("短链服务测试")
class ShortLinkServiceTest {

    @Mock
    private ShortLinkRepository repository;

    @InjectMocks
    private ShortLinkService shortLinkService;

    private final String TEST_URL = "https://example.com/test";
    private final String TEST_CODE = "test123";

    @BeforeEach
    void setUp() {
        lenient().when(repository.existsByCode(anyString())).thenReturn(false);
        lenient().when(repository.save(any(ShortLinkEntity.class))).thenAnswer(invocation -> {
            ShortLinkEntity entity = invocation.getArgument(0);
            entity.setId(1L);
            entity.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
            return entity;
        });
    }

    @Test
    @DisplayName("创建短链 - 基本功能")
    void shouldCreateShortLink_Basic() {
        // When
        ShortLinkEntity result = shortLinkService.create(TEST_URL);

        // Then
        assertNotNull(result);
        assertEquals(TEST_URL, result.getOriginalUrl());
        assertNotNull(result.getCode());
        assertEquals(8, result.getCode().length()); // DEFAULT_CODE_LEN
        assertNotNull(result.getCreatedAt());
        verify(repository).save(any(ShortLinkEntity.class));
    }

    @Test
    @DisplayName("创建短链 - 带activityId参数")
    void shouldCreateShortLink_WithActivityId() {
        String urlWithActivity = TEST_URL + "?activityId=123";
        
        // When
        ShortLinkEntity result = shortLinkService.create(urlWithActivity);

        // Then
        assertNotNull(result);
        assertEquals(urlWithActivity, result.getOriginalUrl());
        assertEquals(123L, result.getActivityId());
        verify(repository).save(any(ShortLinkEntity.class));
    }

    @Test
    @DisplayName("创建短链 - 带inviter参数")
    void shouldCreateShortLink_WithInviter() {
        String urlWithInviter = TEST_URL + "?inviter=456";
        
        // When
        ShortLinkEntity result = shortLinkService.create(urlWithInviter);

        // Then
        assertNotNull(result);
        assertEquals(urlWithInviter, result.getOriginalUrl());
        assertEquals(456L, result.getInviterUserId());
        verify(repository).save(any(ShortLinkEntity.class));
    }

    @Test
    @DisplayName("创建短链 - 带多个参数")
    void shouldCreateShortLink_WithMultipleParams() {
        String urlWithParams = TEST_URL + "?activityId=123&inviter=456&other=value";
        
        // When
        ShortLinkEntity result = shortLinkService.create(urlWithParams);

        // Then
        assertNotNull(result);
        assertEquals(urlWithParams, result.getOriginalUrl());
        assertEquals(123L, result.getActivityId());
        assertEquals(456L, result.getInviterUserId());
        verify(repository).save(any(ShortLinkEntity.class));
    }

    @Test
    @DisplayName("创建短链 - 代码冲突时重新生成")
    void shouldCreateShortLink_WhenCodeConflict() {
        // Given - 第一次生成冲突，第二次成功
        when(repository.existsByCode(anyString()))
                .thenReturn(true)   // 第一次冲突
                .thenReturn(false);  // 第二次成功

        // When
        ShortLinkEntity result = shortLinkService.create(TEST_URL);

        // Then
        assertNotNull(result);
        assertNotNull(result.getCode());
        verify(repository, times(2)).existsByCode(anyString());
        verify(repository).save(any(ShortLinkEntity.class));
    }

    @Test
    @DisplayName("创建短链 - 多次冲突时增加长度")
    void shouldCreateShortLink_WithIncreasedLength() {
        // Given - 所有尝试都冲突
        when(repository.existsByCode(anyString())).thenReturn(true);

        // When
        ShortLinkEntity result = shortLinkService.create(TEST_URL);

        // Then
        assertNotNull(result);
        assertNotNull(result.getCode());
        assertEquals(10, result.getCode().length()); // len + 2
        verify(repository, times(5)).existsByCode(anyString()); // 5次重试
        verify(repository).save(any(ShortLinkEntity.class));
    }

    @Test
    @DisplayName("创建短链 - 无效URL不影响核心功能")
    void shouldCreateShortLink_WithInvalidUrl() {
        String invalidUrl = "not-a-valid-url";

        // When
        ShortLinkEntity result = shortLinkService.create(invalidUrl);

        // Then
        assertNotNull(result);
        assertEquals(invalidUrl, result.getOriginalUrl());
        assertNotNull(result.getCode());
        assertNull(result.getActivityId());
        assertNull(result.getInviterUserId());
        verify(repository).save(any(ShortLinkEntity.class));
    }

    @Test
    @DisplayName("根据代码查找短链 - 找到")
    void shouldFindByCode_WhenExists() {
        // Given
        ShortLinkEntity entity = new ShortLinkEntity();
        entity.setCode(TEST_CODE);
        entity.setOriginalUrl(TEST_URL);
        when(repository.findByCode(TEST_CODE)).thenReturn(Optional.of(entity));

        // When
        Optional<ShortLinkEntity> result = shortLinkService.findByCode(TEST_CODE);

        // Then
        assertTrue(result.isPresent());
        assertEquals(TEST_CODE, result.get().getCode());
        assertEquals(TEST_URL, result.get().getOriginalUrl());
        verify(repository).findByCode(TEST_CODE);
    }

    @Test
    @DisplayName("根据代码查找短链 - 未找到")
    void shouldReturnEmpty_WhenNotExists() {
        // Given
        when(repository.findByCode(TEST_CODE)).thenReturn(Optional.empty());

        // When
        Optional<ShortLinkEntity> result = shortLinkService.findByCode(TEST_CODE);

        // Then
        assertFalse(result.isPresent());
        verify(repository).findByCode(TEST_CODE);
    }

    @Test
    @DisplayName("URL参数解析 - 编码的参数")
    void shouldParseEncodedParams() {
        String urlWithEncoded = TEST_URL + "?activityId=" + java.net.URLEncoder.encode("123", java.nio.charset.StandardCharsets.UTF_8);
        
        // When
        ShortLinkEntity result = shortLinkService.create(urlWithEncoded);

        // Then
        assertEquals(123L, result.getActivityId());
    }

    @Test
    @DisplayName("URL参数解析 - 格式错误的参数")
    void shouldHandleMalformedParams() {
        String urlWithMalformed = TEST_URL + "?activityId=abc&inviter=xyz";
        
        // When
        ShortLinkEntity result = shortLinkService.create(urlWithMalformed);

        // Then
        assertNotNull(result);
        // 应该忽略格式错误的参数，但不影响创建
        verify(repository).save(any(ShortLinkEntity.class));
    }

    @Test
    @DisplayName("生成代码的唯一性验证")
    void shouldGenerateUniqueCodes() {
        // When
        ShortLinkEntity result1 = shortLinkService.create(TEST_URL + "1");
        ShortLinkEntity result2 = shortLinkService.create(TEST_URL + "2");

        // Then
        assertNotEquals(result1.getCode(), result2.getCode());
        verify(repository, times(2)).save(any(ShortLinkEntity.class));
    }
}
