package com.zioinfo.kintex.system.loginhistory;

import com.zioinfo.kintex.common.PageResponse;
import com.zioinfo.kintex.common.text.Masking;
import com.zioinfo.kintex.tenant.TenantContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 로그인 이력 서비스 — 기록(best-effort)·조회. 기록은 인증 흐름을 절대 깨지 않는다(예외 삼킴).
 * 저장 값은 이메일/IP 마스킹만(원문 금지, §0-3).
 */
@Service
public class LoginHistoryService {

    private static final Logger log = LoggerFactory.getLogger(LoginHistoryService.class);
    private final LoginHistoryMapper mapper;

    public LoginHistoryService(LoginHistoryMapper mapper) {
        this.mapper = mapper;
    }

    /** 로그인 성공 기록(best-effort). ip 는 원문을 받아 마스킹 저장. */
    public void recordSuccess(String userId, String email, String ip, String userAgent) {
        record(userId, email, "SUCCESS", null, ip, userAgent);
    }

    /** 로그인 실패 기록(best-effort). reason 은 짧은 요약 코드. */
    public void recordFailure(String email, String reason, String ip, String userAgent) {
        record(null, email, "FAIL", reason, ip, userAgent);
    }

    private void record(String userId, String email, String result, String reason, String ip, String userAgent) {
        try {
            Map<String, Object> p = new HashMap<>();
            p.put("tenantId", TenantContext.currentTenantId());
            p.put("userId", userId);
            p.put("emailMasked", Masking.maskEmail(email));
            p.put("result", result);
            p.put("failReason", reason);
            p.put("ipMasked", Masking.maskIp(ip));
            p.put("userAgent", trunc(userAgent, 300));
            mapper.insert(p);
        } catch (Exception e) {
            // 이력 기록 실패가 로그인 자체를 막아선 안 된다.
            log.warn("[LOGIN_HISTORY] record skipped: {}", e.getClass().getSimpleName());
        }
    }

    public PageResponse<LoginHistoryDto> list(String result, String userId, int page, int size) {
        int p = Math.max(page, 0);
        int s = size <= 0 ? 20 : Math.min(size, 200);
        String tenantId = TenantContext.currentTenantId();
        List<Map<String, Object>> rows = mapper.search(tenantId, result, userId, s, p * s);
        long total = mapper.count(tenantId, result, userId);
        return PageResponse.of(rows.stream().map(LoginHistoryService::toDto).toList(), p, s, total);
    }

    private static LoginHistoryDto toDto(Map<String, Object> r) {
        return new LoginHistoryDto(
                lng(r.get("id")), str(r.get("userId")), str(r.get("emailMasked")), str(r.get("result")),
                str(r.get("failReason")), str(r.get("ipMasked")), str(r.get("userAgent")), str(r.get("createdAt")));
    }
    private static String trunc(String v, int max) {
        if (v == null) return null;
        return v.length() <= max ? v : v.substring(0, max);
    }
    private static String str(Object o) { return o == null ? null : String.valueOf(o); }
    private static long lng(Object o) {
        if (o instanceof Number n) return n.longValue();
        return o == null ? 0L : Long.parseLong(String.valueOf(o));
    }
}
