package logging

import (
	"context"
	"time"
)

// AuditAction represents a security-relevant action.
type AuditAction string

const (
	AuditActionCreate      AuditAction = "create"
	AuditActionRead        AuditAction = "read"
	AuditActionUpdate      AuditAction = "update"
	AuditActionDelete      AuditAction = "delete"
	AuditActionLogin       AuditAction = "login"
	AuditActionLogout      AuditAction = "logout"
	AuditActionGrant       AuditAction = "grant"
	AuditActionRevoke      AuditAction = "revoke"
	AuditActionExecute     AuditAction = "execute"
	AuditActionDeploy      AuditAction = "deploy"
	AuditActionProvision   AuditAction = "provision"
	AuditActionDeprovision AuditAction = "deprovision"
)

// AuditResult represents the outcome of an audited action.
type AuditResult string

const (
	AuditResultSuccess AuditResult = "success"
	AuditResultFailure AuditResult = "failure"
	AuditResultDenied  AuditResult = "denied"
)

// AuditEvent represents a security audit event.
type AuditEvent struct {
	// Timestamp is when the event occurred.
	Timestamp time.Time

	// Action is what was attempted.
	Action AuditAction

	// Resource is what the action was performed on.
	Resource string

	// ResourceID identifies the specific resource.
	ResourceID string

	// Result is the outcome of the action.
	Result AuditResult

	// UserID is who performed the action (empty for system actions).
	UserID string

	// APIKeyID is the API key used (empty for internal actions).
	APIKeyID string

	// RequestID correlates to the HTTP request.
	RequestID string

	// Details contains additional context.
	Details map[string]any
}

// AuditLogger logs security-relevant events.
// Audit logs are always written regardless of log level.
type AuditLogger struct {
	logger *Logger
}

// NewAuditLogger creates a new audit logger.
func NewAuditLogger(l *Logger) *AuditLogger {
	return &AuditLogger{
		logger: l.WithComponent("audit"),
	}
}

// Log logs an audit event.
func (a *AuditLogger) Log(ctx context.Context, event AuditEvent) {
	if event.Timestamp.IsZero() {
		event.Timestamp = time.Now()
	}

	// Build attributes
	attrs := []any{
		FieldAuditAction, string(event.Action),
		FieldAuditResource, event.Resource,
		FieldAuditResult, string(event.Result),
		"resource_id", event.ResourceID,
		"timestamp", event.Timestamp.Format(time.RFC3339),
	}

	if event.UserID != "" {
		attrs = append(attrs, FieldUserID, event.UserID)
	}
	if event.APIKeyID != "" {
		attrs = append(attrs, FieldAPIKeyID, event.APIKeyID)
	}
	if event.RequestID != "" {
		attrs = append(attrs, FieldRequestID, event.RequestID)
	}

	// Add details as individual fields
	for k, v := range event.Details {
		attrs = append(attrs, k, v)
	}

	// Audit logs are always Info level (never skipped)
	a.logger.Info("audit event", attrs...)
}

// LogAction is a convenience method for logging simple actions.
func (a *AuditLogger) LogAction(ctx context.Context, action AuditAction, resource, resourceID string, result AuditResult) {
	// Extract context values if available
	l := FromContext(ctx)
	event := AuditEvent{
		Action:     action,
		Resource:   resource,
		ResourceID: resourceID,
		Result:     result,
	}

	// Try to extract request ID from the context logger
	// This works because the middleware adds these fields
	a.Log(ctx, event)
	_ = l // We might want to extract fields from context in the future
}

// LogSuccess logs a successful action.
func (a *AuditLogger) LogSuccess(ctx context.Context, action AuditAction, resource, resourceID string) {
	a.LogAction(ctx, action, resource, resourceID, AuditResultSuccess)
}

// LogFailure logs a failed action.
func (a *AuditLogger) LogFailure(ctx context.Context, action AuditAction, resource, resourceID string) {
	a.LogAction(ctx, action, resource, resourceID, AuditResultFailure)
}

// LogDenied logs a denied action.
func (a *AuditLogger) LogDenied(ctx context.Context, action AuditAction, resource, resourceID string) {
	a.LogAction(ctx, action, resource, resourceID, AuditResultDenied)
}
