package security

import (
	"os"
	"time"

	"dbbackup/internal/logger"
)

// AuditEvent represents an auditable event
type AuditEvent struct {
	Timestamp time.Time
	User      string
	Action    string
	Resource  string
	Result    string
	Details   map[string]interface{}
}

// AuditLogger provides audit logging functionality
type AuditLogger struct {
	log     logger.Logger
	enabled bool
}

// NewAuditLogger creates a new audit logger
func NewAuditLogger(log logger.Logger, enabled bool) *AuditLogger {
	return &AuditLogger{
		log:     log,
		enabled: enabled,
	}
}

// LogBackupStart logs backup operation start
func (a *AuditLogger) LogBackupStart(user, database, backupType string) {
	if !a.enabled {
		return
	}

	event := AuditEvent{
		Timestamp: time.Now(),
		User:      user,
		Action:    "BACKUP_START",
		Resource:  database,
		Result:    "INITIATED",
		Details: map[string]interface{}{
			"backup_type": backupType,
		},
	}

	a.logEvent(event)
}

// LogBackupComplete logs successful backup completion
func (a *AuditLogger) LogBackupComplete(user, database, archivePath string, sizeBytes int64) {
	if !a.enabled {
		return
	}

	event := AuditEvent{
		Timestamp: time.Now(),
		User:      user,
		Action:    "BACKUP_COMPLETE",
		Resource:  database,
		Result:    "SUCCESS",
		Details: map[string]interface{}{
			"archive_path": archivePath,
			"size_bytes":   sizeBytes,
		},
	}

	a.logEvent(event)
}

// LogBackupFailed logs backup failure
func (a *AuditLogger) LogBackupFailed(user, database string, err error) {
	if !a.enabled {
		return
	}

	event := AuditEvent{
		Timestamp: time.Now(),
		User:      user,
		Action:    "BACKUP_FAILED",
		Resource:  database,
		Result:    "FAILURE",
		Details: map[string]interface{}{
			"error": err.Error(),
		},
	}

	a.logEvent(event)
}

// LogRestoreStart logs restore operation start
func (a *AuditLogger) LogRestoreStart(user, database, archivePath string) {
	if !a.enabled {
		return
	}

	event := AuditEvent{
		Timestamp: time.Now(),
		User:      user,
		Action:    "RESTORE_START",
		Resource:  database,
		Result:    "INITIATED",
		Details: map[string]interface{}{
			"archive_path": archivePath,
		},
	}

	a.logEvent(event)
}

// LogRestoreComplete logs successful restore completion
func (a *AuditLogger) LogRestoreComplete(user, database string, duration time.Duration) {
	if !a.enabled {
		return
	}

	event := AuditEvent{
		Timestamp: time.Now(),
		User:      user,
		Action:    "RESTORE_COMPLETE",
		Resource:  database,
		Result:    "SUCCESS",
		Details: map[string]interface{}{
			"duration_seconds": duration.Seconds(),
		},
	}

	a.logEvent(event)
}

// LogRestoreFailed logs restore failure
func (a *AuditLogger) LogRestoreFailed(user, database string, err error) {
	if !a.enabled {
		return
	}

	event := AuditEvent{
		Timestamp: time.Now(),
		User:      user,
		Action:    "RESTORE_FAILED",
		Resource:  database,
		Result:    "FAILURE",
		Details: map[string]interface{}{
			"error": err.Error(),
		},
	}

	a.logEvent(event)
}

// LogConfigChange logs configuration changes
func (a *AuditLogger) LogConfigChange(user, setting, oldValue, newValue string) {
	if !a.enabled {
		return
	}

	event := AuditEvent{
		Timestamp: time.Now(),
		User:      user,
		Action:    "CONFIG_CHANGE",
		Resource:  setting,
		Result:    "SUCCESS",
		Details: map[string]interface{}{
			"old_value": oldValue,
			"new_value": newValue,
		},
	}

	a.logEvent(event)
}

// LogConnectionAttempt logs database connection attempts
func (a *AuditLogger) LogConnectionAttempt(user, host string, success bool, err error) {
	if !a.enabled {
		return
	}

	result := "SUCCESS"
	details := map[string]interface{}{
		"host": host,
	}

	if !success {
		result = "FAILURE"
		if err != nil {
			details["error"] = err.Error()
		}
	}

	event := AuditEvent{
		Timestamp: time.Now(),
		User:      user,
		Action:    "DB_CONNECTION",
		Resource:  host,
		Result:    result,
		Details:   details,
	}

	a.logEvent(event)
}

// logEvent writes the audit event to log
func (a *AuditLogger) logEvent(event AuditEvent) {
	fields := map[string]interface{}{
		"audit":     true,
		"timestamp": event.Timestamp.Format(time.RFC3339),
		"user":      event.User,
		"action":    event.Action,
		"resource":  event.Resource,
		"result":    event.Result,
	}

	// Merge event details
	for k, v := range event.Details {
		fields[k] = v
	}

	a.log.WithFields(fields).Info("AUDIT")
}

// GetCurrentUser returns the current system user
func GetCurrentUser() string {
	if user := os.Getenv("USER"); user != "" {
		return user
	}
	if user := os.Getenv("USERNAME"); user != "" {
		return user
	}
	return "unknown"
}
