// Package securitylog provides security event logging for audit purposes.
// This captures security-relevant events for monitoring and forensics.
package securitylog

import (
	"time"

	"go.uber.org/zap"
)

// EventType defines the type of security event
type EventType string

const (
	// Authentication events
	EventLoginAttempt     EventType = "LOGIN_ATTEMPT"
	EventLoginSuccess     EventType = "LOGIN_SUCCESS"
	EventLoginFailure     EventType = "LOGIN_FAILURE"
	EventLogout           EventType = "LOGOUT"
	EventSessionRestored  EventType = "SESSION_RESTORED"
	EventSessionExpired   EventType = "SESSION_EXPIRED"
	EventSessionRevoked   EventType = "SESSION_REVOKED"
	EventTokenRefresh     EventType = "TOKEN_REFRESH"
	EventTokenRefreshFail EventType = "TOKEN_REFRESH_FAILURE"

	// Registration events
	EventRegistration       EventType = "REGISTRATION"
	EventEmailVerification  EventType = "EMAIL_VERIFICATION"
	EventOTTRequest         EventType = "OTT_REQUEST"
	EventOTTVerify          EventType = "OTT_VERIFY"
	EventPasswordChallenge  EventType = "PASSWORD_CHALLENGE"

	// Rate limiting events
	EventRateLimitExceeded EventType = "RATE_LIMIT_EXCEEDED"

	// Data access events
	EventCollectionCreate EventType = "COLLECTION_CREATE"
	EventCollectionUpdate EventType = "COLLECTION_UPDATE"
	EventCollectionDelete EventType = "COLLECTION_DELETE"
	EventCollectionAccess EventType = "COLLECTION_ACCESS"

	EventFileUpload   EventType = "FILE_UPLOAD"
	EventFileDownload EventType = "FILE_DOWNLOAD"
	EventFileDelete   EventType = "FILE_DELETE"
	EventFileAccess   EventType = "FILE_ACCESS"
	EventFileOpen     EventType = "FILE_OPEN"

	// Export events
	EventExportStart    EventType = "EXPORT_START"
	EventExportComplete EventType = "EXPORT_COMPLETE"
	EventExportFailure  EventType = "EXPORT_FAILURE"

	// Configuration events
	EventConfigChange          EventType = "CONFIG_CHANGE"
	EventConfigIntegrityFail   EventType = "CONFIG_INTEGRITY_FAILURE"
	EventCloudProviderChange   EventType = "CLOUD_PROVIDER_CHANGE"

	// Security events
	EventSecurityValidationFail EventType = "SECURITY_VALIDATION_FAILURE"
	EventURLValidationFail      EventType = "URL_VALIDATION_FAILURE"
	EventInputValidationFail    EventType = "INPUT_VALIDATION_FAILURE"
	EventPathTraversalAttempt   EventType = "PATH_TRAVERSAL_ATTEMPT"

	// Key management events
	EventMasterKeyDerived EventType = "MASTER_KEY_DERIVED"
	EventMasterKeyCleared EventType = "MASTER_KEY_CLEARED"
	EventPasswordCleared  EventType = "PASSWORD_CLEARED"

	// Application lifecycle events
	EventAppStart    EventType = "APP_START"
	EventAppShutdown EventType = "APP_SHUTDOWN"
)

// EventOutcome indicates the result of an event
type EventOutcome string

const (
	OutcomeSuccess EventOutcome = "SUCCESS"
	OutcomeFailure EventOutcome = "FAILURE"
	OutcomeBlocked EventOutcome = "BLOCKED"
)

// SecurityEvent represents a security-relevant event
type SecurityEvent struct {
	Timestamp   time.Time         `json:"timestamp"`
	EventType   EventType         `json:"event_type"`
	Outcome     EventOutcome      `json:"outcome"`
	UserEmail   string            `json:"user_email,omitempty"` // Masked email
	ResourceID  string            `json:"resource_id,omitempty"`
	ResourceType string           `json:"resource_type,omitempty"`
	Details     map[string]string `json:"details,omitempty"`
	ErrorMsg    string            `json:"error,omitempty"`
}

// Service provides security event logging
type Service struct {
	logger *zap.Logger
}

// New creates a new security logging service
func New(logger *zap.Logger) *Service {
	return &Service{
		logger: logger.Named("security"),
	}
}

// ProvideService is the Wire provider for the security log service
func ProvideService(logger *zap.Logger) *Service {
	return New(logger)
}

// LogEvent logs a security event
func (s *Service) LogEvent(event *SecurityEvent) {
	event.Timestamp = time.Now().UTC()

	fields := []zap.Field{
		zap.String("event_type", string(event.EventType)),
		zap.String("outcome", string(event.Outcome)),
		zap.Time("timestamp", event.Timestamp),
	}

	if event.UserEmail != "" {
		fields = append(fields, zap.String("user_email", event.UserEmail))
	}
	if event.ResourceID != "" {
		fields = append(fields, zap.String("resource_id", event.ResourceID))
	}
	if event.ResourceType != "" {
		fields = append(fields, zap.String("resource_type", event.ResourceType))
	}
	if event.ErrorMsg != "" {
		fields = append(fields, zap.String("error", event.ErrorMsg))
	}
	for k, v := range event.Details {
		fields = append(fields, zap.String("detail_"+k, v))
	}

	switch event.Outcome {
	case OutcomeSuccess:
		s.logger.Info("Security event", fields...)
	case OutcomeFailure:
		s.logger.Warn("Security event", fields...)
	case OutcomeBlocked:
		s.logger.Warn("Security event (blocked)", fields...)
	default:
		s.logger.Info("Security event", fields...)
	}
}

// Helper methods for common events

// LogLoginAttempt logs a login attempt
func (s *Service) LogLoginAttempt(maskedEmail string) {
	s.LogEvent(&SecurityEvent{
		EventType: EventLoginAttempt,
		Outcome:   OutcomeSuccess,
		UserEmail: maskedEmail,
	})
}

// LogLoginSuccess logs a successful login
func (s *Service) LogLoginSuccess(maskedEmail string) {
	s.LogEvent(&SecurityEvent{
		EventType: EventLoginSuccess,
		Outcome:   OutcomeSuccess,
		UserEmail: maskedEmail,
	})
}

// LogLoginFailure logs a failed login
func (s *Service) LogLoginFailure(maskedEmail string, reason string) {
	s.LogEvent(&SecurityEvent{
		EventType: EventLoginFailure,
		Outcome:   OutcomeFailure,
		UserEmail: maskedEmail,
		ErrorMsg:  reason,
	})
}

// LogLogout logs a logout event
func (s *Service) LogLogout(maskedEmail string) {
	s.LogEvent(&SecurityEvent{
		EventType: EventLogout,
		Outcome:   OutcomeSuccess,
		UserEmail: maskedEmail,
	})
}

// LogRateLimitExceeded logs a rate limit exceeded event
func (s *Service) LogRateLimitExceeded(maskedEmail string, operation string) {
	s.LogEvent(&SecurityEvent{
		EventType: EventRateLimitExceeded,
		Outcome:   OutcomeBlocked,
		UserEmail: maskedEmail,
		Details: map[string]string{
			"operation": operation,
		},
	})
}

// LogFileAccess logs a file access event
func (s *Service) LogFileAccess(maskedEmail string, fileID string, operation string, outcome EventOutcome) {
	s.LogEvent(&SecurityEvent{
		EventType:    EventFileAccess,
		Outcome:      outcome,
		UserEmail:    maskedEmail,
		ResourceID:   fileID,
		ResourceType: "file",
		Details: map[string]string{
			"operation": operation,
		},
	})
}

// LogCollectionAccess logs a collection access event
func (s *Service) LogCollectionAccess(maskedEmail string, collectionID string, operation string, outcome EventOutcome) {
	s.LogEvent(&SecurityEvent{
		EventType:    EventCollectionAccess,
		Outcome:      outcome,
		UserEmail:    maskedEmail,
		ResourceID:   collectionID,
		ResourceType: "collection",
		Details: map[string]string{
			"operation": operation,
		},
	})
}

// LogSecurityValidationFailure logs a security validation failure
func (s *Service) LogSecurityValidationFailure(eventType EventType, details map[string]string, errorMsg string) {
	s.LogEvent(&SecurityEvent{
		EventType: eventType,
		Outcome:   OutcomeBlocked,
		Details:   details,
		ErrorMsg:  errorMsg,
	})
}

// LogExport logs an export operation
func (s *Service) LogExport(maskedEmail string, eventType EventType, outcome EventOutcome, details map[string]string) {
	s.LogEvent(&SecurityEvent{
		EventType: eventType,
		Outcome:   outcome,
		UserEmail: maskedEmail,
		Details:   details,
	})
}

// LogConfigChange logs a configuration change
func (s *Service) LogConfigChange(setting string, maskedEmail string) {
	s.LogEvent(&SecurityEvent{
		EventType: EventConfigChange,
		Outcome:   OutcomeSuccess,
		UserEmail: maskedEmail,
		Details: map[string]string{
			"setting": setting,
		},
	})
}

// LogAppLifecycle logs application start/shutdown
func (s *Service) LogAppLifecycle(eventType EventType) {
	s.LogEvent(&SecurityEvent{
		EventType: eventType,
		Outcome:   OutcomeSuccess,
	})
}

// LogKeyManagement logs key management operations
func (s *Service) LogKeyManagement(eventType EventType, maskedEmail string, outcome EventOutcome) {
	s.LogEvent(&SecurityEvent{
		EventType: eventType,
		Outcome:   outcome,
		UserEmail: maskedEmail,
	})
}
