package dev.awesomedev.mirim.service;

import dev.awesomedev.mirim.domain.AuditLog;
import dev.awesomedev.mirim.repository.AuditLogRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * 이 파일이 하는 일:
 * 감사서비스가 "무엇을, 어떤 값으로" 저장하는지 검증한다.
 *
 * 학습 포인트 — ArgumentCaptor: 가짜 저장소(mock)에 "무엇이 넘어왔는지"를 붙잡아 확인한다.
 *   실제 DB 없이도 "record()가 올바른 AuditLog를 만들어 save에 넘겼는가"를 정확히 검증할 수 있다.
 *   시각은 고정 Clock으로 못박아 결정적으로 테스트한다.
 */
class AuditServiceTest {

    private static final Instant FIXED = Instant.parse("2026-09-01T09:00:00Z");
    private final Clock clock = Clock.fixed(FIXED, ZoneOffset.UTC);
    private final AuditLogRepository repository = mock(AuditLogRepository.class);
    private final AuditService service = new AuditService(repository, clock);

    @Test
    @DisplayName("record()는 넘겨받은 값 그대로 + 현재시각으로 감사로그를 저장한다")
    void record_saves_audit_log_with_given_values() {
        service.record("mentor1", "MENTOR", AuditLog.Action.EXPORT_STUDENT_CSV,
                null, "수습생 명단 CSV 다운로드", "203.0.113.9");

        ArgumentCaptor<AuditLog> captor = ArgumentCaptor.forClass(AuditLog.class);
        verify(repository).save(captor.capture());
        AuditLog saved = captor.getValue();

        assertEquals("mentor1", saved.getActor());
        assertEquals("MENTOR", saved.getActorRole());
        assertEquals(AuditLog.Action.EXPORT_STUDENT_CSV, saved.getAction());
        assertEquals("수습생 명단 CSV 다운로드", saved.getDetail());
        assertEquals("203.0.113.9", saved.getIp());
        assertEquals(FIXED, saved.getCreatedAt()); // 고정 시계의 시각이 박힌다
    }

    @Test
    @DisplayName("파기 같은 개별 대상 행위는 targetUserId를 함께 남긴다")
    void record_keeps_target_user_id() {
        service.record("mentor1", "MENTOR", AuditLog.Action.PURGE_STUDENT,
                42L, "학생 #42 파기", "203.0.113.9");

        ArgumentCaptor<AuditLog> captor = ArgumentCaptor.forClass(AuditLog.class);
        verify(repository).save(captor.capture());
        assertEquals(42L, captor.getValue().getTargetUserId());
    }

    @Test
    @DisplayName("recent()는 저장소의 최신순 조회를 그대로 돌려준다")
    void recent_delegates_to_repository() {
        AuditLog one = new AuditLog("mentor1", "MENTOR", AuditLog.Action.VIEW_STUDENT_ROSTER,
                "명단 조회", null, "203.0.113.9", FIXED);
        when(repository.findTop200ByOrderByCreatedAtDesc()).thenReturn(List.of(one));

        List<AuditLog> result = service.recent();

        assertEquals(1, result.size());
        assertEquals(AuditLog.Action.VIEW_STUDENT_ROSTER, result.get(0).getAction());
    }
}
