package org.raddatz.familienarchiv.user;

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.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 java.time.LocalDateTime;
import java.util.Set;
import java.util.UUID;

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

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

    @Autowired InviteTokenRepository inviteTokenRepository;
    @Autowired UserGroupRepository userGroupRepository;
    @Autowired AppUserRepository appUserRepository;

    private UserGroup group;
    private AppUser admin;

    @BeforeEach
    void setUp() {
        inviteTokenRepository.deleteAll();
        userGroupRepository.deleteAll();
        appUserRepository.deleteAll();
        admin = appUserRepository.save(AppUser.builder().email("admin@test.com").password("pw").build());
        group = userGroupRepository.save(UserGroup.builder().name("Familie").build());
    }

    // ─── existsActiveWithGroupId ──────────────────────────────────────────────

    @Test
    void existsActiveWithGroupId_returnsTrueForActiveInviteLinkedToGroup() {
        inviteTokenRepository.save(token(t -> t));

        assertThat(inviteTokenRepository.existsActiveWithGroupId(group.getId())).isTrue();
    }

    @Test
    void existsActiveWithGroupId_returnsFalseWhenInviteIsRevoked() {
        inviteTokenRepository.save(token(t -> t.revoked(true)));

        assertThat(inviteTokenRepository.existsActiveWithGroupId(group.getId())).isFalse();
    }

    @Test
    void existsActiveWithGroupId_returnsFalseWhenInviteIsExpired() {
        inviteTokenRepository.save(token(t -> t.expiresAt(LocalDateTime.now().minusDays(1))));

        assertThat(inviteTokenRepository.existsActiveWithGroupId(group.getId())).isFalse();
    }

    @Test
    void existsActiveWithGroupId_returnsFalseWhenInviteIsExhausted() {
        inviteTokenRepository.save(token(t -> t.maxUses(1).useCount(1)));

        assertThat(inviteTokenRepository.existsActiveWithGroupId(group.getId())).isFalse();
    }

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

    private InviteToken token(java.util.function.UnaryOperator<InviteToken.InviteTokenBuilder> customizer) {
        InviteToken.InviteTokenBuilder builder = InviteToken.builder()
                .code(UUID.randomUUID().toString().replace("-", "").substring(0, 10))
                .groupIds(new java.util.HashSet<>(Set.of(group.getId())))
                .createdBy(admin);
        return customizer.apply(builder).build();
    }
}
