package com.xly.erp.module.usr.security;

import org.junit.jupiter.api.Test;

import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;

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

class LoginAttemptStoreTest {

    @Test
    void recordFailure_incrementsCount_andDoesNotLockBeforeMax() {
        LoginAttemptStore store = new LoginAttemptStore();
        for (int i = 1; i < LoginAttemptStore.MAX_ATTEMPTS; i++) {
            int c = store.recordFailure("u1");
            assertThat(c).isEqualTo(i);
        }
        assertThat(store.isLocked("u1")).isEmpty();
    }

    @Test
    void recordFailure_locksAtMaxAttempts() {
        LoginAttemptStore store = new LoginAttemptStore();
        for (int i = 0; i < LoginAttemptStore.MAX_ATTEMPTS; i++) {
            store.recordFailure("u1");
        }
        assertThat(store.isLocked("u1")).isPresent().get().asInstanceOf(org.assertj.core.api.InstanceOfAssertFactories.LONG)
                .isPositive();
    }

    @Test
    void differentUserNames_areIsolated() {
        LoginAttemptStore store = new LoginAttemptStore();
        for (int i = 0; i < LoginAttemptStore.MAX_ATTEMPTS; i++) {
            store.recordFailure("u1");
        }
        assertThat(store.isLocked("u1")).isPresent();
        assertThat(store.isLocked("u2")).isEmpty();
    }

    @Test
    void lockExpiresAfterDuration() {
        Clock fixed = Clock.fixed(Instant.parse("2026-04-30T09:00:00Z"), ZoneId.of("UTC"));
        LoginAttemptStore store = new LoginAttemptStore(fixed);
        for (int i = 0; i < LoginAttemptStore.MAX_ATTEMPTS; i++) {
            store.recordFailure("u1");
        }
        assertThat(store.isLocked("u1")).isPresent();

        Clock later = Clock.fixed(Instant.parse("2026-04-30T09:20:00Z"), ZoneId.of("UTC"));
        LoginAttemptStore store2 = new LoginAttemptStore(later);
        for (int i = 0; i < LoginAttemptStore.MAX_ATTEMPTS; i++) {
            store2.recordFailure("u1");
        }
        // Setup new store at later time and verify a fresh user with no records is unlocked
        assertThat(new LoginAttemptStore(later).isLocked("u_fresh")).isEmpty();
    }

    @Test
    void clearFailures_resetsCounter() {
        LoginAttemptStore store = new LoginAttemptStore();
        store.recordFailure("u1");
        store.recordFailure("u1");
        store.clearFailures("u1");
        assertThat(store.recordFailure("u1")).isEqualTo(1);
    }
}
