package org.raddatz.familienarchiv.timeline;

import org.junit.jupiter.api.Test;
import org.raddatz.familienarchiv.PostgresContainerConfig;
import org.raddatz.familienarchiv.document.DatePrecision;
import org.raddatz.familienarchiv.person.Person;
import org.raddatz.familienarchiv.person.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.transaction.support.TransactionTemplate;
import software.amazon.awssdk.services.s3.S3Client;

import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

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

/**
 * Verifies that {@link TimelineService#assemble} does not throw
 * {@link org.hibernate.LazyInitializationException} when events have linked persons.
 *
 * <p>No class-level {@code @Transactional} — each test method runs without an outer
 * transaction, matching production behaviour (controller has no {@code @Transactional}).
 * If {@code assemble()} lacks {@code @Transactional(readOnly=true)}, accessing
 * {@code ev.getPersons()} on detached entities throws LazyInitializationException.
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ActiveProfiles("test")
@Import(PostgresContainerConfig.class)
class TimelineServiceLazyLoadTest {

    @MockitoBean
    S3Client s3Client;

    @Autowired
    TransactionTemplate transactionTemplate;

    @Autowired
    TimelineService timelineService;

    @Autowired
    TimelineEventRepository timelineEventRepository;

    @Autowired
    PersonRepository personRepository;

    @Test
    void assemble_does_not_throw_when_event_has_linked_persons() {
        UUID actorId = UUID.randomUUID();
        // Commit outside any test-managed transaction so entities are detached on return
        transactionTemplate.execute(status -> {
            Person person = personRepository.save(Person.builder().lastName("Müller").build());
            timelineEventRepository.save(TimelineEvent.builder()
                    .title("Linked event")
                    .type(EventType.HISTORICAL)
                    .eventDate(LocalDate.of(1914, 7, 28))
                    .precision(DatePrecision.DAY)
                    .createdBy(actorId)
                    .updatedBy(actorId)
                    .persons(new HashSet<>(Set.of(person)))
                    .build());
            return null;
        });

        assertDoesNotThrow(() -> timelineService.assemble(new TimelineFilter(null, null, null, null, null)));
    }
}
