package admin

import (
	"context"
	"encoding/json"
	"log"
)

// SecurityLog records admin-side security events (login failures, allowlist
// rejections, lockouts) to both the structured logger and the audit_log table.
//
// Per doc/02 §1 the admin backend records ONLY security events — never routine
// access logs.
type SecurityLog struct {
	store  Store
	logger *log.Logger
}

// NewSecurityLog creates a SecurityLog. A nil logger falls back to the
// standard logger.
func NewSecurityLog(store Store, logger *log.Logger) *SecurityLog {
	if logger == nil {
		logger = log.Default()
	}
	return &SecurityLog{store: store, logger: logger}
}

func (s *SecurityLog) write(ctx context.Context, actor, action, target string, meta map[string]any) {
	if s == nil {
		return
	}
	metaJSON := ""
	if meta != nil {
		if b, err := json.Marshal(meta); err == nil {
			metaJSON = string(b)
		}
	}
	s.logger.Printf("admin security event action=%s actor=%s target=%s", action, actor, target)
	if s.store != nil {
		if err := s.store.WriteAudit(ctx, actor, action, target, metaJSON); err != nil {
			s.logger.Printf("admin security event audit write failed: %v", err)
		}
	}
}

// LoginFail records a failed login attempt.
func (s *SecurityLog) LoginFail(ctx context.Context, username, ip, reason string) {
	s.write(ctx, safeActor(username), "admin_login_fail", "ip:"+ip, map[string]any{"reason": reason})
}

// LoginLocked records a login attempt against a locked-out account.
func (s *SecurityLog) LoginLocked(ctx context.Context, username, ip string) {
	s.write(ctx, safeActor(username), "admin_login_locked", "ip:"+ip, nil)
}

// LoginOK records a successful login.
func (s *SecurityLog) LoginOK(ctx context.Context, username, ip string) {
	s.write(ctx, safeActor(username), "admin_login_ok", "ip:"+ip, nil)
}

// IPBlocked records an allowlist rejection.
func (s *SecurityLog) IPBlocked(ctx context.Context, ip, path string) {
	s.write(ctx, "-", "admin_ip_blocked", "ip:"+ip, map[string]any{"path": path})
}

func safeActor(username string) string {
	if username == "" {
		return "-"
	}
	if len(username) > 64 {
		return username[:64]
	}
	return username
}
