package com.mosquito.project.persistence.repository;

import com.mosquito.project.persistence.entity.ShortLinkEntity;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.TestPropertySource;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;

/**
 * ShortLinkRepository 数据访问层测试
 * 测试短链接实体的CRUD操作和自定义查询方法
 */
@DataJpaTest
@org.springframework.context.annotation.Import(com.mosquito.project.config.TestCacheConfig.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY)
@TestPropertySource(properties = {
        "spring.cache.type=NONE",
        "spring.jpa.hibernate.ddl-auto=create-drop",
        "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration"
})
class ShortLinkRepositoryTest {

    @Autowired
    private ShortLinkRepository shortLinkRepository;

    @Test
    void shouldSaveAndFindShortLinkById() {
        // 准备测试数据
        OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
        ShortLinkEntity entity = new ShortLinkEntity();
        entity.setCode("test123");
        entity.setOriginalUrl("https://example.com/page1");
        entity.setActivityId(1L);
        entity.setInviterUserId(100L);
        entity.setCreatedAt(now);

        // 保存实体
        ShortLinkEntity saved = shortLinkRepository.save(entity);

        // 验证保存成功
        assertNotNull(saved.getId(), "保存后ID不应为空");
        assertEquals("test123", saved.getCode());
        assertEquals("https://example.com/page1", saved.getOriginalUrl());

        // 通过ID查询验证
        Optional<ShortLinkEntity> found = shortLinkRepository.findById(saved.getId());
        assertTrue(found.isPresent(), "应该能通过ID找到实体");
        assertEquals("test123", found.get().getCode());
    }

    @Test
    void shouldFindByCodeSuccessfully() {
        // 准备并保存测试数据
        OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
        ShortLinkEntity entity = new ShortLinkEntity();
        entity.setCode("findme");
        entity.setOriginalUrl("https://test.com/target");
        entity.setCreatedAt(now);
        shortLinkRepository.save(entity);

        // 通过code查询
        Optional<ShortLinkEntity> found = shortLinkRepository.findByCode("findme");

        // 验证查询结果
        assertTrue(found.isPresent(), "应该能通过code找到实体");
        assertEquals("findme", found.get().getCode());
        assertEquals("https://test.com/target", found.get().getOriginalUrl());
    }

    @Test
    void shouldReturnEmptyWhenCodeNotExists() {
        // 查询不存在的code
        Optional<ShortLinkEntity> found = shortLinkRepository.findByCode("nonexistent");

        // 验证返回空Optional
        assertFalse(found.isPresent(), "不存在的code应该返回空Optional");
    }

    @Test
    void shouldCheckExistsByCodeSuccessfully() {
        // 准备并保存测试数据
        OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
        ShortLinkEntity entity = new ShortLinkEntity();
        entity.setCode("exists123");
        entity.setOriginalUrl("https://example.com");
        entity.setCreatedAt(now);
        shortLinkRepository.save(entity);

        // 验证存在的code
        assertTrue(shortLinkRepository.existsByCode("exists123"), "已存在的code应该返回true");

        // 验证不存在的code
        assertFalse(shortLinkRepository.existsByCode("notexists"), "不存在的code应该返回false");
    }

    @Test
    void shouldUpdateShortLinkSuccessfully() {
        // 准备并保存初始数据
        OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
        ShortLinkEntity entity = new ShortLinkEntity();
        entity.setCode("update123");
        entity.setOriginalUrl("https://old.com");
        entity.setActivityId(1L);
        entity.setCreatedAt(now);
        ShortLinkEntity saved = shortLinkRepository.save(entity);

        // 更新实体
        saved.setOriginalUrl("https://new.com");
        saved.setActivityId(2L);
        ShortLinkEntity updated = shortLinkRepository.save(saved);

        // 验证更新成功
        assertEquals("https://new.com", updated.getOriginalUrl());
        assertEquals(2L, updated.getActivityId());

        // 重新查询验证
        ShortLinkEntity found = shortLinkRepository.findById(saved.getId()).orElseThrow();
        assertEquals("https://new.com", found.getOriginalUrl());
        assertEquals(2L, found.getActivityId());
    }

    @Test
    void shouldDeleteShortLinkSuccessfully() {
        // 准备并保存测试数据
        OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
        ShortLinkEntity entity = new ShortLinkEntity();
        entity.setCode("delete123");
        entity.setOriginalUrl("https://delete.com");
        entity.setCreatedAt(now);
        ShortLinkEntity saved = shortLinkRepository.save(entity);
        Long id = saved.getId();

        // 删除实体
        shortLinkRepository.deleteById(id);

        // 验证删除成功
        assertFalse(shortLinkRepository.existsById(id), "删除后不应再找到实体");
        assertFalse(shortLinkRepository.existsByCode("delete123"), "删除后code也不应存在");
    }

    @Test
    void shouldMaintainCodeUniqueness() {
        // 准备第一个实体
        OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
        ShortLinkEntity entity1 = new ShortLinkEntity();
        entity1.setCode("unique123");
        entity1.setOriginalUrl("https://first.com");
        entity1.setCreatedAt(now);
        shortLinkRepository.save(entity1);

        // 准备第二个实体，使用相同的code
        ShortLinkEntity entity2 = new ShortLinkEntity();
        entity2.setCode("unique123");
        entity2.setOriginalUrl("https://second.com");
        entity2.setCreatedAt(now);

        // 验证保存重复code会抛出异常
        assertThrows(Exception.class, () -> {
            shortLinkRepository.saveAndFlush(entity2);
        }, "重复的code应该抛出异常");
    }

    @Test
    void shouldFindWithActivityAndInviterInfo() {
        // 准备带有关联信息的实体
        OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
        ShortLinkEntity entity = new ShortLinkEntity();
        entity.setCode("full123");
        entity.setOriginalUrl("https://full.com");
        entity.setActivityId(42L);
        entity.setInviterUserId(99L);
        entity.setCreatedAt(now);
        shortLinkRepository.save(entity);

        // 查询并验证所有字段
        ShortLinkEntity found = shortLinkRepository.findByCode("full123").orElseThrow();
        assertEquals(42L, found.getActivityId(), "活动ID应正确保存");
        assertEquals(99L, found.getInviterUserId(), "邀请人ID应正确保存");
        assertNotNull(found.getCreatedAt(), "创建时间应正确保存");
    }
}
