package dev.awesomedev.mirim.service;

import dev.awesomedev.mirim.domain.AuditLog;
import dev.awesomedev.mirim.repository.AuditLogRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 이 파일이 하는 일:
 * 개인정보 접근·처리 "사건"을 감사로그 테이블에 남기고, 최근 기록을 읽어 준다.
 *
 * 학습 포인트 — "이중 기록": DB(영속·조회용) + 표준 로그(운영 중 즉시 확인용).
 *   DB에 남기면 멘토 화면에서 "누가 언제 열람했나"를 조회·필터할 수 있다.
 *   동시에 slf4j로도 찍어, 서버 로그를 보는 사람이 흐름 속에서 바로 알아챌 수 있다.
 *   단, 비밀번호 같은 민감값은 어느 쪽에도 남기지 않는다(AuditLog 주석 참고).
 */
@Service
public class AuditService {

    private static final Logger log = LoggerFactory.getLogger(AuditService.class);

    private final AuditLogRepository auditLogRepository;
    private final Clock clock;

    public AuditService(AuditLogRepository auditLogRepository, Clock clock) {
        this.auditLogRepository = auditLogRepository;
        this.clock = clock;
    }

    /** 개인정보 접근·처리 사건 한 건을 기록한다. */
    @Transactional
    public void record(String actor, String actorRole, AuditLog.Action action,
                       Long targetUserId, String detail, String ip) {
        // 학습 포인트: DB 저장 "전에" 먼저 로그로 남긴다.
        //   비가역 행위(파기 등)는 본작업이 이미 커밋된 뒤 이 감사가 별도 트랜잭션으로 실행된다.
        //   만약 audit_log INSERT가 실패(DB 순단 등)하면 감사기록이 통째로 사라질 수 있는데,
        //   저장 전에 로그부터 찍어 두면 최소한 서버 로그엔 "그 사건이 있었다"가 남는다.
        //   (완전한 원자성은 텔레그램 발송 같은 되돌릴 수 없는 부작용과 충돌하므로 택하지 않는다.)
        log.info("감사기록 actor={} role={} action={} target={} ip={} detail={}",
                actor, actorRole, action, targetUserId, ip, detail);
        auditLogRepository.save(new AuditLog(actor, actorRole, action, detail, targetUserId, ip, clock.instant()));
    }

    /** 멘토 화면용 — 최근 감사기록(최신순 상위 200건). */
    @Transactional(readOnly = true)
    public List<AuditLog> recent() {
        return auditLogRepository.findTop200ByOrderByCreatedAtDesc();
    }
}
