package com.example.volunteer;

import com.example.volunteer.model.Event;
import com.example.volunteer.model.Signup;
import com.example.volunteer.model.Volunteer;
import com.example.volunteer.repository.EventRepository;
import com.example.volunteer.repository.SignupRepository;
import com.example.volunteer.repository.VolunteerRepository;
import com.example.volunteer.service.SignupQueryService;
import com.example.volunteer.service.VolunteerHours;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;

import java.time.LocalDate;
import java.util.List;

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

/**
 * ============================================================================
 * 样卷 Q5(b) — 数据层单元测试
 * ============================================================================
 *
 * 【题目 / Question】
 * EN — Code a test case for unit testing, verifying the creation of a new entity using the
 *      Spring testing framework. (2 marks)
 * 中 — 用 Spring 测试框架写一个单元测试，验证实体的创建。（2 分）
 *
 * 【为什么是 @DataJpaTest / Why this slice】
 * EN — @DataJpaTest boots ONLY the JPA layer against an embedded database and rolls back
 *      after each test, which is exactly what "create this entity" needs. @SpringBootTest
 *      would start the whole application (slow) and @WebMvcTest has no database at all.
 * 中 — @DataJpaTest 只启动 JPA 层 + 内嵌数据库，每个测试后自动回滚，正好对应“创建实体”；
 *      @SpringBootTest 会起整个应用（慢），@WebMvcTest 根本没有数据库。
 *
 * 【注意 / Note】
 * EN — SignupQueryService is @Import-ed because @DataJpaTest does not scan plain @Service
 *      classes; without it the aggregate test could not run.
 * 中 — 需要 @Import(SignupQueryService.class)，因为 @DataJpaTest 不扫描普通 @Service。
 */
@DataJpaTest
@Import(SignupQueryService.class)
class SignupRepositoryTest {

    @Autowired private SignupRepository signupRepository;
    @Autowired private EventRepository eventRepository;
    @Autowired private VolunteerRepository volunteerRepository;
    @Autowired private SignupQueryService signupQueryService;

    private Event event;
    private Volunteer alice;

    @BeforeEach
    void setUp() {
        event = eventRepository.save(
                new Event("Beach Cleanup", LocalDate.now(), "East Coast Park", 5));
        alice = volunteerRepository.save(
                new Volunteer("Alice", "alice@example.com", "91234567"));
    }

    /** 样卷 Q5(b) 本体：保存 + 断言 */
    @Test
    void createsSignup() {
        Signup signup = new Signup(alice, LocalDate.now(), 4);
        signup.setEvent(event);

        Signup saved = signupRepository.save(signup);

        assertNotNull(saved.getId(), "id should be generated");
        assertTrue(signupRepository.existsByEventIdAndVolunteerId(event.getId(), alice.getId()));
    }

    /** 样卷 Q4(b)：聚合查询 */
    @Test
    void aggregatesTotalHours() {
        Signup first = new Signup(alice, LocalDate.now().minusDays(2), 4);
        first.setEvent(event);
        Signup second = new Signup(alice, LocalDate.now(), 3);
        second.setEvent(event);
        signupRepository.saveAll(List.of(first, second));

        List<VolunteerHours> top = signupQueryService.topVolunteers(5, 10);

        assertTrue(top.stream().anyMatch(v ->
                        v.volunteerId().equals(alice.getId()) && v.totalHours() == 7),
                "Alice should have 7 hours in total");
    }
}
