package de.fete.adapter.out.persistence;

import static org.assertj.core.api.Assertions.assertThat;

import de.fete.TestcontainersConfig;
import de.fete.domain.model.Event;
import de.fete.domain.model.EventToken;
import de.fete.domain.model.OrganizerToken;
import de.fete.domain.port.out.EventRepository;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;

@SpringBootTest
@Import(TestcontainersConfig.class)
class EventPersistenceAdapterTest {

  @Autowired
  private EventRepository eventRepository;

  @Test
  void saveReturnsEventWithGeneratedId() {
    Event event = buildEvent();

    Event saved = eventRepository.save(event);

    assertThat(saved.id()).isNotNull();
    assertThat(saved.title()).isEqualTo("Test Event");
  }

  @Test
  void savedEventIsFoundByEventToken() {
    Event event = buildEvent();
    Event saved = eventRepository.save(event);

    Optional<Event> found = eventRepository.findByEventToken(saved.eventToken());

    assertThat(found).isPresent();
    assertThat(found.get().title()).isEqualTo("Test Event");
    assertThat(found.get().id()).isEqualTo(saved.id());
  }

  @Test
  void findByUnknownEventTokenReturnsEmpty() {
    Optional<Event> found = eventRepository.findByEventToken(EventToken.generate());

    assertThat(found).isEmpty();
  }

  @Test
  void allFieldsRoundTripCorrectly() {
    OffsetDateTime dateTime =
        OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2));
    LocalDate expiryDate = LocalDate.of(2026, 7, 15);
    OffsetDateTime createdAt =
        OffsetDateTime.of(2026, 3, 4, 12, 0, 0, 0, ZoneOffset.UTC);

    var event = new Event(
        null,
        EventToken.generate(),
        OrganizerToken.generate(),
        "Full Event",
        "A detailed description",
        dateTime,
        ZoneId.of("Europe/Berlin"),
        "Berlin, Germany",
        expiryDate,
        createdAt,
        false,
        null);

    Event saved = eventRepository.save(event);
    Event found = eventRepository.findByEventToken(saved.eventToken()).orElseThrow();

    assertThat(found.eventToken()).isEqualTo(event.eventToken());
    assertThat(found.organizerToken()).isEqualTo(event.organizerToken());
    assertThat(found.title()).isEqualTo("Full Event");
    assertThat(found.description()).isEqualTo("A detailed description");
    assertThat(found.dateTime().toInstant()).isEqualTo(dateTime.toInstant());
    assertThat(found.timezone()).isEqualTo(ZoneId.of("Europe/Berlin"));
    assertThat(found.location()).isEqualTo("Berlin, Germany");
    assertThat(found.expiryDate()).isEqualTo(expiryDate);
    assertThat(found.createdAt().toInstant()).isEqualTo(createdAt.toInstant());
  }

  private Event buildEvent() {
    return new Event(
        null,
        EventToken.generate(),
        OrganizerToken.generate(),
        "Test Event",
        "Test description",
        OffsetDateTime.now().plusDays(7),
        ZoneId.of("Europe/Berlin"),
        "Somewhere",
        LocalDate.now().plusDays(30),
        OffsetDateTime.now(),
        false,
        null);
  }
}
