package org.raddatz.familienarchiv.notification;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.raddatz.familienarchiv.PostgresContainerConfig;
import org.raddatz.familienarchiv.config.FlywayConfig;
import org.raddatz.familienarchiv.user.AppUser;
import org.raddatz.familienarchiv.notification.Notification;
import org.raddatz.familienarchiv.notification.NotificationType;
import org.raddatz.familienarchiv.user.AppUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

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

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import({PostgresContainerConfig.class, FlywayConfig.class})
class NotificationRepositoryTest {

    @Autowired NotificationRepository notificationRepository;
    @Autowired AppUserRepository appUserRepository;

    private AppUser userA;
    private AppUser userB;

    @BeforeEach
    void setUp() {
        notificationRepository.deleteAll();
        appUserRepository.deleteAll();
        userA = appUserRepository.save(AppUser.builder().email("userA@example.com").password("pw").build());
        userB = appUserRepository.save(AppUser.builder().email("userB@example.com").password("pw").build());
    }

    // ─── findByRecipientIdAndTypeAndReadFalse ─────────────────────────────────

    @Test
    void returnsOnlyUnreadMentions_forTargetUser() {
        notificationRepository.save(mention(userA, false)); // ✓ match
        notificationRepository.save(mention(userA, true));  // read — excluded
        notificationRepository.save(reply(userA, false));   // REPLY — excluded
        notificationRepository.save(mention(userB, false)); // different user — excluded

        Page<Notification> result = notificationRepository
                .findByRecipientIdAndTypeAndReadFalseOrderByCreatedAtDesc(
                        userA.getId(), NotificationType.MENTION, Pageable.ofSize(10));

        assertThat(result.getContent()).hasSize(1);
        assertThat(result.getContent().get(0).getRecipient().getId()).isEqualTo(userA.getId());
        assertThat(result.getContent().get(0).getType()).isEqualTo(NotificationType.MENTION);
        assertThat(result.getContent().get(0).isRead()).isFalse();
    }

    @Test
    void returnsEmpty_whenAllMentionsAreRead() {
        notificationRepository.save(mention(userA, true));

        Page<Notification> result = notificationRepository
                .findByRecipientIdAndTypeAndReadFalseOrderByCreatedAtDesc(
                        userA.getId(), NotificationType.MENTION, Pageable.ofSize(10));

        assertThat(result.getContent()).isEmpty();
    }

    @Test
    void respectsSizeLimit() {
        for (int i = 0; i < 5; i++) {
            notificationRepository.save(mention(userA, false));
        }

        Page<Notification> result = notificationRepository
                .findByRecipientIdAndTypeAndReadFalseOrderByCreatedAtDesc(
                        userA.getId(), NotificationType.MENTION, Pageable.ofSize(3));

        assertThat(result.getContent()).hasSize(3);
        assertThat(result.getTotalElements()).isEqualTo(5);
    }

    // ─── findByRecipientIdAndType (without read filter) ──────────────────────

    @Test
    void findByType_returnsBothReadAndUnreadMentions() {
        notificationRepository.save(mention(userA, false)); // unread
        notificationRepository.save(mention(userA, true));  // read — should also be included
        notificationRepository.save(reply(userA, false));   // REPLY — excluded
        notificationRepository.save(mention(userB, false)); // different user — excluded

        Page<Notification> result = notificationRepository
                .findByRecipientIdAndTypeOrderByCreatedAtDesc(
                        userA.getId(), NotificationType.MENTION, Pageable.ofSize(10));

        assertThat(result.getContent()).hasSize(2);
        assertThat(result.getContent()).allMatch(n -> n.getType() == NotificationType.MENTION);
        assertThat(result.getContent()).allMatch(n -> n.getRecipient().getId().equals(userA.getId()));
    }

    // ─── helpers ─────────────────────────────────────────────────────────────

    private Notification mention(AppUser recipient, boolean read) {
        return Notification.builder()
                .recipient(recipient)
                .type(NotificationType.MENTION)
                .actorName("Tester")
                .read(read)
                .build();
    }

    private Notification reply(AppUser recipient, boolean read) {
        return Notification.builder()
                .recipient(recipient)
                .type(NotificationType.REPLY)
                .actorName("Tester")
                .read(read)
                .build();
    }
}
