package main

import (
	"context"
	"crypto/x509"
	"database/sql"
	"encoding/asn1"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/google/uuid"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
	"golang.org/x/crypto/bcrypt"

	"certigo-addon-backend/internal/core"
	"certigo-addon-backend/providers"
)

// OID zu Name Mapping (OpenSSL Format)
var oidToName = map[string]string{
	"2.5.29.15":          "X509v3 Key Usage",
	"2.5.29.17":          "X509v3 Subject Alternative Name",
	"2.5.29.19":          "X509v3 Basic Constraints",
	"2.5.29.31":          "X509v3 CRL Distribution Points",
	"2.5.29.32":          "X509v3 Certificate Policies",
	"2.5.29.35":          "X509v3 Authority Key Identifier",
	"2.5.29.37":          "X509v3 Extended Key Usage",
	"2.5.29.14":          "X509v3 Subject Key Identifier",
	"1.3.6.1.5.5.7.1.1":  "Authority Information Access",
	"1.3.6.1.5.5.7.48.1": "OCSP",
	"1.3.6.1.5.5.7.48.2": "CA Issuers",
}

// Extended Key Usage OIDs (OpenSSL Format)
var extendedKeyUsageOIDs = map[string]string{
	"1.3.6.1.5.5.7.3.1": "TLS Web Server Authentication",
	"1.3.6.1.5.5.7.3.2": "TLS Web Client Authentication",
	"1.3.6.1.5.5.7.3.3": "Code Signing",
	"1.3.6.1.5.5.7.3.4": "E-mail Protection",
	"1.3.6.1.5.5.7.3.8": "Time Stamping",
	"1.3.6.1.5.5.7.3.9": "OCSP Signing",
	"1.3.6.1.5.5.7.3.5": "IPsec End System",
	"1.3.6.1.5.5.7.3.6": "IPsec Tunnel",
	"1.3.6.1.5.5.7.3.7": "IPsec User",
}

// Key Usage Flags
var keyUsageFlags = map[int]string{
	0: "Digital Signature",
	1: "Content Commitment",
	2: "Key Encipherment",
	3: "Data Encipherment",
	4: "Key Agreement",
	5: "Key Cert Sign",
	6: "CRL Sign",
	7: "Encipher Only",
	8: "Decipher Only",
}

func getExtensionName(oid string) string {
	if name, ok := oidToName[oid]; ok {
		return name
	}
	return "Unknown Extension"
}

func parseExtensionValue(oid string, value []byte, csr *x509.CertificateRequest) (string, []string) {
	switch oid {
	case "2.5.29.37": // Extended Key Usage
		return parseExtendedKeyUsage(value)
	case "2.5.29.15": // Key Usage
		return parseKeyUsage(value)
	case "2.5.29.19": // Basic Constraints
		return parseBasicConstraints(value)
	case "2.5.29.17": // Subject Alternative Name
		return parseSubjectAlternativeName(csr)
	default:
		return hex.EncodeToString(value), nil
	}
}

func parseSubjectAlternativeName(csr *x509.CertificateRequest) (string, []string) {
	var parts []string

	// DNS Names
	for _, dns := range csr.DNSNames {
		parts = append(parts, fmt.Sprintf("DNS:%s", dns))
	}

	// Email Addresses
	for _, email := range csr.EmailAddresses {
		parts = append(parts, fmt.Sprintf("email:%s", email))
	}

	// IP Addresses
	for _, ip := range csr.IPAddresses {
		parts = append(parts, fmt.Sprintf("IP:%s", ip.String()))
	}

	// URIs
	for _, uri := range csr.URIs {
		parts = append(parts, fmt.Sprintf("URI:%s", uri.String()))
	}

	if len(parts) > 0 {
		return strings.Join(parts, ", "), parts
	}
	return "No Subject Alternative Name", nil
}

func parseExtendedKeyUsage(value []byte) (string, []string) {
	var oids []asn1.ObjectIdentifier
	_, err := asn1.Unmarshal(value, &oids)
	if err != nil {
		return hex.EncodeToString(value), nil
	}

	var purposes []string
	for _, oid := range oids {
		oidStr := oid.String()
		if purpose, ok := extendedKeyUsageOIDs[oidStr]; ok {
			purposes = append(purposes, purpose)
		} else {
			purposes = append(purposes, oidStr)
		}
	}

	if len(purposes) > 0 {
		// Format wie OpenSSL: jede Purpose auf eigener Zeile
		return strings.Join(purposes, "\n                    "), purposes
	}
	return hex.EncodeToString(value), nil
}

func parseKeyUsage(value []byte) (string, []string) {
	var bits asn1.BitString
	_, err := asn1.Unmarshal(value, &bits)
	if err != nil {
		return hex.EncodeToString(value), nil
	}

	var usages []string
	for i := 0; i < len(bits.Bytes)*8 && i < 9; i++ {
		if bits.At(i) == 1 {
			if usage, ok := keyUsageFlags[i]; ok {
				usages = append(usages, usage)
			}
		}
	}

	if len(usages) > 0 {
		return strings.Join(usages, ", "), usages
	}
	return "No key usage specified", nil
}

func parseBasicConstraints(value []byte) (string, []string) {
	var constraints struct {
		IsCA       bool `asn1:"optional"`
		MaxPathLen int  `asn1:"optional,default:-1"`
	}
	_, err := asn1.Unmarshal(value, &constraints)
	if err != nil {
		return hex.EncodeToString(value), nil
	}

	var parts []string
	if constraints.IsCA {
		parts = append(parts, "CA: true")
	} else {
		parts = append(parts, "CA: false")
	}
	if constraints.MaxPathLen >= 0 {
		parts = append(parts, fmt.Sprintf("Path Length: %d", constraints.MaxPathLen))
	}

	return strings.Join(parts, ", "), parts
}

type HealthResponse struct {
	Status  string `json:"status"`
	Message string `json:"message"`
	Time    string `json:"time"`
}

type StatsResponse struct {
	Spaces       int `json:"spaces"`
	FQDNs        int `json:"fqdns"`
	CSRs         int `json:"csrs"`
	Certificates int `json:"certificates"`
	Users        int `json:"users"`
}

type Space struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	CreatedAt   string `json:"createdAt"`
}

type CreateSpaceRequest struct {
	Name        string `json:"name"`
	Description string `json:"description"`
}

type FQDN struct {
	ID          string `json:"id"`
	SpaceID     string `json:"spaceId"`
	FQDN        string `json:"fqdn"`
	Description string `json:"description"`
	CreatedAt   string `json:"createdAt"`
}

type CreateFQDNRequest struct {
	FQDN        string `json:"fqdn"`
	Description string `json:"description"`
}

type Extension struct {
	ID          string   `json:"id"`
	OID         string   `json:"oid"`
	Name        string   `json:"name"`
	Critical    bool     `json:"critical"`
	Value       string   `json:"value"`
	Description string   `json:"description"`
	Purposes    []string `json:"purposes,omitempty"`
}

type CSR struct {
	ID                 string      `json:"id"`
	FQDNID             string      `json:"fqdnId"`
	SpaceID            string      `json:"spaceId"`
	FQDN               string      `json:"fqdn"`
	CSRPEM             string      `json:"csrPem"`
	Subject            string      `json:"subject"`
	PublicKeyAlgorithm string      `json:"publicKeyAlgorithm"`
	SignatureAlgorithm string      `json:"signatureAlgorithm"`
	KeySize            int         `json:"keySize"`
	DNSNames           []string    `json:"dnsNames"`
	EmailAddresses     []string    `json:"emailAddresses"`
	IPAddresses        []string    `json:"ipAddresses"`
	URIs               []string    `json:"uris"`
	Extensions         []Extension `json:"extensions"`
	CreatedAt          string      `json:"createdAt"`
}

// User struct für Benutzer
type User struct {
	ID        string   `json:"id"`
	Username  string   `json:"username"`
	Email     string   `json:"email"`
	IsAdmin   bool     `json:"isAdmin"`
	Enabled   bool     `json:"enabled"`
	CreatedAt string   `json:"createdAt"`
	GroupIDs  []string `json:"groupIds,omitempty"`
}

// PermissionLevel definiert die Berechtigungsstufen
type PermissionLevel string

const (
	PermissionRead       PermissionLevel = "READ"
	PermissionReadWrite  PermissionLevel = "READ_WRITE"
	PermissionFullAccess PermissionLevel = "FULL_ACCESS"
)

// PermissionGroup struct für Berechtigungsgruppen
type PermissionGroup struct {
	ID          string          `json:"id"`
	Name        string          `json:"name"`
	Description string          `json:"description"`
	Permission  PermissionLevel `json:"permission"`
	SpaceIDs    []string        `json:"spaceIds"`
	CreatedAt   string          `json:"createdAt"`
}

// CreatePermissionGroupRequest struct für Gruppen-Erstellung
type CreatePermissionGroupRequest struct {
	Name        string          `json:"name"`
	Description string          `json:"description"`
	Permission  PermissionLevel `json:"permission"`
	SpaceIDs    []string        `json:"spaceIds"`
}

// UpdatePermissionGroupRequest struct für Gruppen-Update
type UpdatePermissionGroupRequest struct {
	Name        string          `json:"name"`
	Description string          `json:"description"`
	Permission  PermissionLevel `json:"permission"`
	SpaceIDs    []string        `json:"spaceIds"`
}

// UpdateUserRequest struct für Benutzer-Update
type UpdateUserRequest struct {
	Username    string   `json:"username,omitempty"`
	Email       string   `json:"email,omitempty"`
	Password    string   `json:"password,omitempty"`
	OldPassword string   `json:"oldPassword,omitempty"`
	IsAdmin     *bool    `json:"isAdmin,omitempty"`
	Enabled     *bool    `json:"enabled,omitempty"`
	GroupIDs    []string `json:"groupIds,omitempty"`
}

// CreateUserRequest struct für Benutzer-Erstellung
type CreateUserRequest struct {
	Username string   `json:"username"`
	Email    string   `json:"email"`
	Password string   `json:"password"`
	IsAdmin  bool     `json:"isAdmin,omitempty"`
	GroupIDs []string `json:"groupIds,omitempty"`
}

// MessageResponse struct für einfache Nachrichten
type MessageResponse struct {
	Message string `json:"message"`
}

// AuditLog struct für Audit-Logs
type AuditLog struct {
	ID           string `json:"id"`
	Timestamp    string `json:"timestamp"`
	UserID       string `json:"userId,omitempty"`
	Username     string `json:"username,omitempty"`
	Action       string `json:"action"`
	ResourceType string `json:"resourceType"`
	ResourceID   string `json:"resourceId,omitempty"`
	Details      string `json:"details,omitempty"`
	IPAddress    string `json:"ipAddress,omitempty"`
	UserAgent    string `json:"userAgent,omitempty"`
}

var db *sql.DB
var auditService *core.AuditService

func initDB() {
	var err error
	// SQLite Connection String mit Timeout und WAL Mode für bessere Concurrency
	// _busy_timeout erhöht die Wartezeit bei Locks
	db, err = sql.Open("sqlite3", "./spaces.db?_foreign_keys=1&_journal_mode=WAL&_timeout=10000&_busy_timeout=10000")
	if err != nil {
		log.Fatal("Fehler beim Öffnen der Datenbank:", err)
	}

	// Setze Connection Pool Settings
	db.SetMaxOpenConns(1) // SQLite unterstützt nur eine Verbindung gleichzeitig
	db.SetMaxIdleConns(1)

	// Teste die Verbindung mit Retry
	log.Println("Teste Datenbank-Verbindung...")
	maxRetries := 5
	for i := 0; i < maxRetries; i++ {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
		err := db.PingContext(ctx)
		cancel()
		if err != nil {
			if i < maxRetries-1 {
				log.Printf("Datenbank-Verbindung fehlgeschlagen, versuche erneut (%d/%d)...", i+1, maxRetries)
				time.Sleep(time.Second * 2)
				continue
			}
			log.Fatal("Fehler beim Verbinden mit der Datenbank nach mehreren Versuchen:", err)
		}
		log.Println("Datenbank-Verbindung erfolgreich")
		break
	}

	// Aktiviere Foreign Keys (auch über Connection String, aber zur Sicherheit nochmal)
	log.Println("Aktiviere Foreign Keys...")
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, "PRAGMA foreign_keys = ON")
	cancel()
	if err != nil {
		log.Fatal("Fehler beim Aktivieren der Foreign Keys:", err)
	}

	// Prüfe und bereinige WAL-Dateien falls nötig
	log.Println("Führe WAL-Checkpoint aus...")
	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, "PRAGMA wal_checkpoint(TRUNCATE)")
	cancel()
	if err != nil {
		log.Printf("Warnung: WAL-Checkpoint fehlgeschlagen: %v", err)
	}

	// Erstelle Tabelle falls sie nicht existiert
	log.Println("Erstelle spaces-Tabelle...")
	createTableSQL := `
	CREATE TABLE IF NOT EXISTS spaces (
		id TEXT PRIMARY KEY,
		name TEXT NOT NULL,
		description TEXT,
		created_at DATETIME NOT NULL
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createTableSQL)
	cancel()
	if err != nil {
		log.Fatal("Fehler beim Erstellen der Tabelle:", err)
	}

	// Erstelle FQDN-Tabelle
	log.Println("Erstelle fqdns-Tabelle...")
	createFQDNTableSQL := `
	CREATE TABLE IF NOT EXISTS fqdns (
		id TEXT PRIMARY KEY,
		space_id TEXT NOT NULL,
		fqdn TEXT NOT NULL,
		description TEXT,
		created_at DATETIME NOT NULL,
		FOREIGN KEY (space_id) REFERENCES spaces(id) ON DELETE CASCADE
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createFQDNTableSQL)
	cancel()
	if err != nil {
		log.Fatal("Fehler beim Erstellen der FQDN-Tabelle:", err)
	}

	// Erstelle CSR-Tabelle
	log.Println("Erstelle csrs-Tabelle...")
	createCSRTableSQL := `
	CREATE TABLE IF NOT EXISTS csrs (
		id TEXT PRIMARY KEY,
		fqdn_id TEXT NOT NULL,
		space_id TEXT NOT NULL,
		fqdn TEXT NOT NULL,
		csr_pem TEXT NOT NULL,
		subject TEXT,
		public_key_algorithm TEXT,
		signature_algorithm TEXT,
		key_size INTEGER,
		dns_names TEXT,
		email_addresses TEXT,
		ip_addresses TEXT,
		uris TEXT,
		extensions TEXT,
		created_at DATETIME NOT NULL,
		FOREIGN KEY (fqdn_id) REFERENCES fqdns(id) ON DELETE CASCADE,
		FOREIGN KEY (space_id) REFERENCES spaces(id) ON DELETE CASCADE
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createCSRTableSQL)
	cancel()
	if err != nil {
		log.Fatal("Fehler beim Erstellen der CSR-Tabelle:", err)
	}

	// Füge Extensions-Spalte hinzu, falls sie nicht existiert (für bestehende Datenbanken)
	// Prüfe zuerst, ob die Spalte bereits existiert
	log.Println("Prüfe Extensions-Spalte...")
	var columnExists bool
	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	rows, err := db.QueryContext(ctx, "PRAGMA table_info(csrs)")
	cancel()
	if err == nil {
		defer rows.Close()
		for rows.Next() {
			var cid int
			var name string
			var dataType string
			var notNull int
			var defaultValue interface{}
			var pk int
			if err := rows.Scan(&cid, &name, &dataType, &notNull, &defaultValue, &pk); err == nil {
				if name == "extensions" {
					columnExists = true
					break
				}
			}
		}
		rows.Close()
	}

	// Füge Spalte nur hinzu, wenn sie nicht existiert
	if !columnExists {
		log.Println("Füge Extensions-Spalte hinzu...")
		ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
		_, err = db.ExecContext(ctx, "ALTER TABLE csrs ADD COLUMN extensions TEXT")
		cancel()
		if err != nil {
			// Ignoriere "duplicate column" Fehler, da die Spalte möglicherweise zwischenzeitlich hinzugefügt wurde
			if !strings.Contains(err.Error(), "duplicate column") {
				log.Printf("Fehler beim Hinzufügen der Extensions-Spalte: %v", err)
			}
		} else {
			log.Println("Extensions-Spalte zur csrs-Tabelle hinzugefügt")
		}
	} else {
		log.Println("Extensions-Spalte existiert bereits")
	}

	// Erstelle Zertifikat-Tabelle
	log.Println("Erstelle certificates-Tabelle...")
	createCertificateTableSQL := `
	CREATE TABLE IF NOT EXISTS certificates (
		id TEXT PRIMARY KEY,
		fqdn_id TEXT NOT NULL,
		space_id TEXT NOT NULL,
		csr_id TEXT NOT NULL,
		certificate_id TEXT NOT NULL,
		provider_id TEXT NOT NULL,
		certificate_pem TEXT,
		status TEXT NOT NULL,
		created_at DATETIME NOT NULL,
		FOREIGN KEY (fqdn_id) REFERENCES fqdns(id) ON DELETE CASCADE,
		FOREIGN KEY (space_id) REFERENCES spaces(id) ON DELETE CASCADE,
		FOREIGN KEY (csr_id) REFERENCES csrs(id) ON DELETE CASCADE
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createCertificateTableSQL)
	cancel()
	if err != nil {
		if strings.Contains(err.Error(), "database is locked") {
			log.Fatal("Datenbank ist gesperrt. Bitte beenden Sie alle anderen Prozesse, die die Datenbank verwenden (z.B. andere go run main.go Instanzen).")
		}
		log.Fatal("Fehler beim Erstellen der Zertifikat-Tabelle:", err)
	}

	// Erstelle Users-Tabelle
	log.Println("Erstelle users-Tabelle...")
	createUsersTableSQL := `
	CREATE TABLE IF NOT EXISTS users (
		id TEXT PRIMARY KEY,
		username TEXT NOT NULL UNIQUE,
		email TEXT NOT NULL UNIQUE,
		password_hash TEXT NOT NULL,
		is_admin INTEGER DEFAULT 0,
		enabled INTEGER DEFAULT 1,
		created_at DATETIME NOT NULL
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createUsersTableSQL)
	cancel()
	if err != nil {
		if strings.Contains(err.Error(), "database is locked") {
			log.Fatal("Datenbank ist gesperrt. Bitte beenden Sie alle anderen Prozesse, die die Datenbank verwenden (z.B. andere go run main.go Instanzen).")
		}
		log.Fatal("Fehler beim Erstellen der Users-Tabelle:", err)
	}

	log.Println("Datenbank erfolgreich initialisiert")

	// Füge is_admin Spalte hinzu falls nicht vorhanden
	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, "ALTER TABLE users ADD COLUMN is_admin INTEGER DEFAULT 0")
	cancel()
	if err != nil && !strings.Contains(err.Error(), "duplicate column") {
		log.Printf("Hinweis: is_admin-Spalte könnte bereits existieren: %v", err)
	}

	// Füge enabled Spalte hinzu falls nicht vorhanden
	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, "ALTER TABLE users ADD COLUMN enabled INTEGER DEFAULT 1")
	cancel()
	if err != nil && !strings.Contains(err.Error(), "duplicate column") {
		log.Printf("Hinweis: enabled-Spalte könnte bereits existieren: %v", err)
	}

	// Erstelle Audit-Log-Tabelle
	log.Println("Erstelle audit_logs-Tabelle...")
	createAuditLogsTableSQL := `
	CREATE TABLE IF NOT EXISTS audit_logs (
		id TEXT PRIMARY KEY,
		timestamp DATETIME NOT NULL,
		user_id TEXT,
		username TEXT,
		action TEXT NOT NULL,
		resource_type TEXT NOT NULL,
		resource_id TEXT,
		details TEXT,
		ip_address TEXT,
		user_agent TEXT
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createAuditLogsTableSQL)
	cancel()
	if err != nil {
		if strings.Contains(err.Error(), "database is locked") {
			log.Fatal("Datenbank ist gesperrt. Bitte beenden Sie alle anderen Prozesse, die die Datenbank verwenden (z.B. andere go run main.go Instanzen).")
		}
		log.Fatal("Fehler beim Erstellen der Audit-Log-Tabelle:", err)
	}

	// Erstelle Index für bessere Performance
	log.Println("Erstelle Indizes für audit_logs...")
	createIndexSQL := `
	CREATE INDEX IF NOT EXISTS idx_audit_logs_timestamp ON audit_logs(timestamp DESC);
	CREATE INDEX IF NOT EXISTS idx_audit_logs_user_id ON audit_logs(user_id);
	CREATE INDEX IF NOT EXISTS idx_audit_logs_action ON audit_logs(action);
	CREATE INDEX IF NOT EXISTS idx_audit_logs_resource_type ON audit_logs(resource_type);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createIndexSQL)
	cancel()
	if err != nil {
		log.Printf("Warnung: Fehler beim Erstellen der Indizes: %v", err)
	}

	// Erstelle Default Admin-User falls nicht vorhanden
	createDefaultAdmin()

	// Initialisiere AuditService (muss nach DB-Initialisierung passieren)
	auditService = core.NewAuditService(db)
	if auditService == nil {
		log.Fatal("Fehler: AuditService konnte nicht initialisiert werden")
	}
	log.Println("AuditService erfolgreich initialisiert")

	// Erstelle Upload-Ordner für Profilbilder
	avatarDir := "uploads/avatars"
	if err := os.MkdirAll(avatarDir, 0755); err != nil {
		log.Printf("Warnung: Konnte Avatar-Ordner nicht erstellen: %v", err)
	} else {
		log.Printf("Avatar-Ordner erstellt: %s", avatarDir)
	}

	// Erstelle Permission Groups-Tabelle
	log.Println("Erstelle permission_groups-Tabelle...")
	createPermissionGroupsTableSQL := `
	CREATE TABLE IF NOT EXISTS permission_groups (
		id TEXT PRIMARY KEY,
		name TEXT NOT NULL,
		description TEXT,
		permission TEXT NOT NULL,
		created_at DATETIME NOT NULL
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createPermissionGroupsTableSQL)
	cancel()
	if err != nil {
		if strings.Contains(err.Error(), "database is locked") {
			log.Fatal("datenbank ist gesperrt. Bitte beenden Sie alle anderen Prozesse, die die Datenbank verwenden.")
		}
		log.Fatal("Fehler beim Erstellen der permission_groups-Tabelle:", err)
	}

	// Erstelle group_spaces-Tabelle für Space-Zuweisungen
	log.Println("Erstelle group_spaces-Tabelle...")
	createGroupSpacesTableSQL := `
	CREATE TABLE IF NOT EXISTS group_spaces (
		group_id TEXT NOT NULL,
		space_id TEXT NOT NULL,
		PRIMARY KEY (group_id, space_id),
		FOREIGN KEY (group_id) REFERENCES permission_groups(id) ON DELETE CASCADE,
		FOREIGN KEY (space_id) REFERENCES spaces(id) ON DELETE CASCADE
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createGroupSpacesTableSQL)
	cancel()
	if err != nil {
		if strings.Contains(err.Error(), "database is locked") {
			log.Fatal("datenbank ist gesperrt. Bitte beenden Sie alle anderen Prozesse, die die Datenbank verwenden.")
		}
		log.Fatal("Fehler beim Erstellen der group_spaces-Tabelle:", err)
	}

	// Erstelle user_groups-Tabelle für Benutzer-Gruppen-Zuweisungen
	log.Println("Erstelle user_groups-Tabelle...")
	createUserGroupsTableSQL := `
	CREATE TABLE IF NOT EXISTS user_groups (
		user_id TEXT NOT NULL,
		group_id TEXT NOT NULL,
		PRIMARY KEY (user_id, group_id),
		FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
		FOREIGN KEY (group_id) REFERENCES permission_groups(id) ON DELETE CASCADE
	);`

	ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
	_, err = db.ExecContext(ctx, createUserGroupsTableSQL)
	cancel()
	if err != nil {
		if strings.Contains(err.Error(), "database is locked") {
			log.Fatal("datenbank ist gesperrt. Bitte beenden Sie alle anderen Prozesse, die die Datenbank verwenden.")
		}
		log.Fatal("Fehler beim Erstellen der user_groups-Tabelle:", err)
	}

	log.Println("Berechtigungssystem-Tabellen erfolgreich erstellt")
}

func createDefaultAdmin() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	// Prüfe ob bereits ein Admin-User mit UID "admin" existiert
	var count int
	err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM users WHERE id = 'admin'").Scan(&count)
	if err != nil {
		log.Printf("Fehler beim Prüfen des Admin-Users: %v", err)
		return
	}

	if count > 0 {
		log.Println("Admin-User mit UID 'admin' existiert bereits")
		// Stelle sicher, dass der Admin-User als Admin markiert ist
		_, err = db.ExecContext(ctx, "UPDATE users SET is_admin = 1 WHERE id = 'admin'")
		if err != nil {
			log.Printf("Warnung: Konnte Admin-Status nicht setzen: %v", err)
		} else {
			log.Println("Admin-User ist als Administrator markiert")
		}
		// Prüfe ob das Passwort noch "admin" ist (für Debugging)
		var storedHash string
		err = db.QueryRowContext(ctx, "SELECT password_hash FROM users WHERE id = 'admin'").Scan(&storedHash)
		if err == nil {
			// Teste ob das Passwort "admin" ist
			testErr := bcrypt.CompareHashAndPassword([]byte(storedHash), []byte("admin"))
			if testErr == nil {
				log.Println("Admin-User Passwort ist korrekt gesetzt")
			} else {
				log.Println("Warnung: Admin-User Passwort ist nicht 'admin'")
			}
		}
		return
	}

	// Migration: Falls ein Admin-User mit username='admin' aber anderer UID existiert, migriere ihn
	var existingAdminID string
	err = db.QueryRowContext(ctx, "SELECT id FROM users WHERE username = 'admin' AND id != 'admin' LIMIT 1").Scan(&existingAdminID)
	if err == nil {
		log.Printf("Migriere bestehenden Admin-User von UID '%s' zu UID 'admin'", existingAdminID)
		// Hole alle Daten des alten Admin-Users
		var oldUsername, oldEmail, oldPasswordHash string
		var oldIsAdmin, oldEnabled int
		var oldCreatedAt string
		err = db.QueryRowContext(ctx, "SELECT username, email, password_hash, is_admin, enabled, created_at FROM users WHERE id = ?", existingAdminID).
			Scan(&oldUsername, &oldEmail, &oldPasswordHash, &oldIsAdmin, &oldEnabled, &oldCreatedAt)
		if err == nil {
			// Erstelle neuen Admin-User mit UID 'admin'
			_, err = db.ExecContext(ctx,
				"INSERT INTO users (id, username, email, password_hash, is_admin, enabled, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
				"admin", oldUsername, oldEmail, oldPasswordHash, oldIsAdmin, oldEnabled, oldCreatedAt)
			if err == nil {
				// Migriere user_groups Zuweisungen
				_, err = db.ExecContext(ctx, "UPDATE user_groups SET user_id = 'admin' WHERE user_id = ?", existingAdminID)
				if err != nil {
					log.Printf("Warnung: Konnte user_groups nicht migrieren: %v", err)
				}
				// Lösche den alten User (CASCADE sollte user_groups automatisch löschen)
				_, err = db.ExecContext(ctx, "DELETE FROM users WHERE id = ?", existingAdminID)
				if err == nil {
					log.Printf("✓ Admin-User erfolgreich zu UID 'admin' migriert")
					return
				} else {
					log.Printf("Warnung: Konnte alten Admin-User nicht löschen: %v", err)
				}
			} else {
				log.Printf("Warnung: Konnte neuen Admin-User nicht erstellen: %v", err)
			}
		} else {
			log.Printf("Warnung: Konnte Daten des alten Admin-Users nicht lesen: %v", err)
		}
	}

	// Erstelle Default Admin-User mit fester UID "admin"
	adminPassword := "admin" // Default Passwort - sollte in Produktion geändert werden
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(adminPassword), bcrypt.DefaultCost)
	if err != nil {
		log.Printf("Fehler beim Hashen des Admin-Passworts: %v", err)
		return
	}

	adminID := "admin" // Feste UID statt UUID
	createdAt := time.Now().Format(time.RFC3339)

	_, err = db.ExecContext(ctx,
		"INSERT INTO users (id, username, email, password_hash, is_admin, enabled, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
		adminID, "admin", "admin@certigo.local", string(hashedPassword), 1, 1, createdAt)
	if err != nil {
		log.Printf("Fehler beim Erstellen des Admin-Users: %v", err)
		return
	}

	log.Println("✓ Default Admin-User erstellt: UID='admin', username='admin', password='admin'")
	log.Printf("  User ID: %s", adminID)
	log.Printf("  Email: admin@certigo.local")
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	response := HealthResponse{
		Status:  "ok",
		Message: "Backend ist erreichbar",
		Time:    time.Now().Format(time.RFC3339),
	}

	json.NewEncoder(w).Encode(response)
}

func getStatsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	var spacesCount, fqdnsCount, csrsCount, certificatesCount, usersCount int

	// Zähle Spaces
	err := db.QueryRow("SELECT COUNT(*) FROM spaces").Scan(&spacesCount)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Statistiken", http.StatusInternalServerError)
		log.Printf("Fehler beim Zählen der Spaces: %v", err)
		return
	}

	// Zähle FQDNs
	err = db.QueryRow("SELECT COUNT(*) FROM fqdns").Scan(&fqdnsCount)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Statistiken", http.StatusInternalServerError)
		log.Printf("Fehler beim Zählen der FQDNs: %v", err)
		return
	}

	// Zähle CSRs
	err = db.QueryRow("SELECT COUNT(*) FROM csrs").Scan(&csrsCount)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Statistiken", http.StatusInternalServerError)
		log.Printf("Fehler beim Zählen der CSRs: %v", err)
		return
	}

	// Zähle Zertifikate
	err = db.QueryRow("SELECT COUNT(*) FROM certificates").Scan(&certificatesCount)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Statistiken", http.StatusInternalServerError)
		log.Printf("Fehler beim Zählen der Zertifikate: %v", err)
		return
	}

	// Zähle Benutzer
	err = db.QueryRow("SELECT COUNT(*) FROM users").Scan(&usersCount)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Statistiken", http.StatusInternalServerError)
		log.Printf("Fehler beim Zählen der Benutzer: %v", err)
		return
	}

	response := StatsResponse{
		Spaces:       spacesCount,
		FQDNs:        fqdnsCount,
		CSRs:         csrsCount,
		Certificates: certificatesCount,
		Users:        usersCount,
	}

	json.NewEncoder(w).Encode(response)
}

func getSpacesHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Hole Benutzer-ID
	userID, _ := getUserFromRequest(r)

	// Hole alle Spaces, auf die der Benutzer Zugriff hat
	accessibleSpaceIDs, err := getAccessibleSpaceIDs(userID)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigungen: %v", err)
		return
	}

	// Wenn der Benutzer keinen Zugriff auf Spaces hat, gebe leeres Array zurück
	if len(accessibleSpaceIDs) == 0 {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode([]Space{})
		return
	}

	// Baue Query mit IN-Klausel für die zugänglichen Spaces
	placeholders := make([]string, len(accessibleSpaceIDs))
	args := make([]interface{}, len(accessibleSpaceIDs))
	for i, spaceID := range accessibleSpaceIDs {
		placeholders[i] = "?"
		args[i] = spaceID
	}

	query := fmt.Sprintf("SELECT id, name, description, created_at FROM spaces WHERE id IN (%s) ORDER BY created_at DESC", strings.Join(placeholders, ","))

	rows, err := db.Query(query, args...)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Spaces", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Spaces: %v", err)
		return
	}
	defer rows.Close()

	spaces := make([]Space, 0)
	for rows.Next() {
		var space Space
		var createdAt time.Time
		var description sql.NullString

		err := rows.Scan(&space.ID, &space.Name, &description, &createdAt)
		if err != nil {
			http.Error(w, "Fehler beim Lesen der Daten", http.StatusInternalServerError)
			log.Printf("Fehler beim Lesen der Daten: %v", err)
			return
		}

		if description.Valid {
			space.Description = description.String
		} else {
			space.Description = ""
		}
		space.CreatedAt = createdAt.Format(time.RFC3339)
		spaces = append(spaces, space)
	}

	if err = rows.Err(); err != nil {
		http.Error(w, "Fehler beim Verarbeiten der Daten", http.StatusInternalServerError)
		log.Printf("Fehler beim Verarbeiten der Daten: %v", err)
		return
	}

	// Stelle sicher, dass immer ein Array zurückgegeben wird
	if spaces == nil {
		spaces = []Space{}
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(spaces)
}

func createSpaceHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Prüfe Berechtigung: Nur FULL_ACCESS darf Spaces erstellen
	userID, username := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	// Prüfe ob User Admin ist - Admins haben immer Vollzugriff
	isAdmin, err := isUserAdmin(userID)
	if err != nil {
		log.Printf("Fehler beim Prüfen des Admin-Status: %v", err)
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		return
	}

	// Prüfe, ob der Benutzer FULL_ACCESS hat (ohne Space-Beschränkung)
	permissions, err := getUserPermissions(userID)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Berechtigungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Berechtigungen: %v", err)
		return
	}

	// Admin oder HasFullAccess erlaubt Space-Erstellung
	hasFullAccess := isAdmin || permissions.HasFullAccess

	// Wenn nicht Admin, prüfe auch Gruppen
	if !isAdmin && len(permissions.Groups) > 0 {
		for _, group := range permissions.Groups {
			if group.Permission == PermissionFullAccess {
				hasFullAccess = true
				break
			}
		}
	}

	if !hasFullAccess {
		http.Error(w, "Keine Berechtigung zum Erstellen von Spaces. Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	var req CreateSpaceRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	if req.Name == "" {
		http.Error(w, "Name is required", http.StatusBadRequest)
		return
	}

	// Generiere eindeutige UUID
	id := uuid.New().String()
	createdAt := time.Now()

	// Speichere in Datenbank
	_, err = db.Exec(
		"INSERT INTO spaces (id, name, description, created_at) VALUES (?, ?, ?, ?)",
		id, req.Name, req.Description, createdAt,
	)
	if err != nil {
		http.Error(w, "Fehler beim Speichern des Space", http.StatusInternalServerError)
		log.Printf("Fehler beim Speichern des Space: %v", err)
		return
	}

	newSpace := Space{
		ID:          id,
		Name:        req.Name,
		Description: req.Description,
		CreatedAt:   createdAt.Format(time.RFC3339),
	}

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(newSpace)

	// Audit-Log: Space erstellt
	if auditService != nil {
		ipAddress, userAgent := getRequestInfo(r)
		auditService.Track(r.Context(), "CREATE", "space", id, userID, username, map[string]interface{}{
			"name":        req.Name,
			"description": req.Description,
			"message":     fmt.Sprintf("Space erstellt: %s", req.Name),
		}, ipAddress, userAgent)
	}
}

func deleteSpaceHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "DELETE, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	id := vars["id"]

	if id == "" {
		http.Error(w, "Space ID ist erforderlich", http.StatusBadRequest)
		return
	}

	// Prüfe Berechtigung: Nur FULL_ACCESS darf Spaces löschen
	userID, username := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasPermission, err := hasPermission(userID, id, PermissionFullAccess)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasPermission {
		http.Error(w, "Keine Berechtigung zum Löschen von Spaces. Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	// Prüfe ob der Space existiert
	var exists bool
	err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM spaces WHERE id = ?)", id).Scan(&exists)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen des Space", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen des Space: %v", err)
		return
	}

	if !exists {
		http.Error(w, "Space nicht gefunden", http.StatusNotFound)
		return
	}

	// Prüfe ob FQDNs vorhanden sind
	var fqdnCount int
	err = db.QueryRow("SELECT COUNT(*) FROM fqdns WHERE space_id = ?", id).Scan(&fqdnCount)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der FQDNs", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der FQDNs: %v", err)
		return
	}

	// Prüfe Query-Parameter für Mitlöschen
	deleteFqdns := r.URL.Query().Get("deleteFqdns") == "true"

	if fqdnCount > 0 && !deleteFqdns {
		http.Error(w, "Space enthält noch FQDNs. Bitte löschen Sie zuerst die FQDNs oder wählen Sie die Option zum Mitlöschen.", http.StatusConflict)
		return
	}

	// Beginne Transaktion für atomares Löschen
	tx, err := db.Begin()
	if err != nil {
		http.Error(w, "Fehler beim Starten der Transaktion", http.StatusInternalServerError)
		log.Printf("Fehler beim Starten der Transaktion: %v", err)
		return
	}
	defer tx.Rollback()

	// Lösche FQDNs zuerst, wenn gewünscht
	if deleteFqdns && fqdnCount > 0 {
		_, err = tx.Exec("DELETE FROM fqdns WHERE space_id = ?", id)
		if err != nil {
			http.Error(w, "Fehler beim Löschen der FQDNs", http.StatusInternalServerError)
			log.Printf("Fehler beim Löschen der FQDNs: %v", err)
			return
		}
		log.Printf("Gelöscht: %d FQDNs für Space %s", fqdnCount, id)
	}

	// Lösche den Space
	result, err := tx.Exec("DELETE FROM spaces WHERE id = ?", id)
	if err != nil {
		http.Error(w, "Fehler beim Löschen des Space", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen des Space: %v", err)
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		tx.Rollback()
		http.Error(w, "Fehler beim Prüfen der gelöschten Zeilen", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der gelöschten Zeilen: %v", err)
		return
	}

	if rowsAffected == 0 {
		tx.Rollback()
		http.Error(w, "Space nicht gefunden", http.StatusNotFound)
		return
	}

	// Committe die Transaktion
	err = tx.Commit()
	if err != nil {
		http.Error(w, "Fehler beim Speichern der Änderungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Committen der Transaktion: %v", err)
		return
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{"message": "Space erfolgreich gelöscht"})

	// Audit-Log: Space gelöscht
	ipAddress, userAgent := getRequestInfo(r)
	details := map[string]interface{}{
		"message": fmt.Sprintf("Space gelöscht: %s", id),
	}
	if deleteFqdns && fqdnCount > 0 {
		details["fqdnsDeleted"] = fqdnCount
		details["message"] = fmt.Sprintf("Space gelöscht: %s (mit %d FQDNs)", id, fqdnCount)
	}
	auditService.Track(r.Context(), "DELETE", "space", id, userID, username, details, ipAddress, userAgent)
}

func getSpaceFqdnCountHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["id"]

	if spaceID == "" {
		http.Error(w, "Space ID ist erforderlich", http.StatusBadRequest)
		return
	}

	// Prüfe Berechtigung: Benutzer muss Zugriff auf den Space haben
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasAccess, err := hasSpaceAccess(userID, spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasAccess {
		http.Error(w, "Keine Berechtigung für diesen Space", http.StatusForbidden)
		return
	}

	var count int
	err = db.QueryRow("SELECT COUNT(*) FROM fqdns WHERE space_id = ?", spaceID).Scan(&count)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der FQDN-Anzahl", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der FQDN-Anzahl: %v", err)
		return
	}

	json.NewEncoder(w).Encode(map[string]int{"count": count})
}

func getFqdnsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["id"]

	if spaceID == "" {
		http.Error(w, "Space ID ist erforderlich", http.StatusBadRequest)
		return
	}

	// Prüfe Berechtigung: Benutzer muss Zugriff auf den Space haben
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasAccess, err := hasSpaceAccess(userID, spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasAccess {
		http.Error(w, "Keine Berechtigung für diesen Space", http.StatusForbidden)
		return
	}

	// Prüfe ob der Space existiert
	var exists bool
	err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM spaces WHERE id = ?)", spaceID).Scan(&exists)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen des Space", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen des Space: %v", err)
		return
	}

	if !exists {
		http.Error(w, "Space nicht gefunden", http.StatusNotFound)
		return
	}

	rows, err := db.Query("SELECT id, space_id, fqdn, description, created_at FROM fqdns WHERE space_id = ? ORDER BY created_at DESC", spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der FQDNs", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der FQDNs: %v", err)
		return
	}
	defer rows.Close()

	var fqdns []FQDN
	for rows.Next() {
		var fqdn FQDN
		var createdAt time.Time
		var description sql.NullString
		err := rows.Scan(&fqdn.ID, &fqdn.SpaceID, &fqdn.FQDN, &description, &createdAt)
		if err != nil {
			http.Error(w, "Fehler beim Lesen der Daten", http.StatusInternalServerError)
			log.Printf("Fehler beim Lesen der Daten: %v", err)
			return
		}
		if description.Valid {
			fqdn.Description = description.String
		} else {
			fqdn.Description = ""
		}
		fqdn.CreatedAt = createdAt.Format(time.RFC3339)
		fqdns = append(fqdns, fqdn)
	}

	if err = rows.Err(); err != nil {
		http.Error(w, "Fehler beim Verarbeiten der Daten", http.StatusInternalServerError)
		log.Printf("Fehler beim Verarbeiten der Daten: %v", err)
		return
	}

	if fqdns == nil {
		fqdns = []FQDN{}
	}

	json.NewEncoder(w).Encode(fqdns)
}

func createFqdnHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["id"]

	if spaceID == "" {
		http.Error(w, "Space ID ist erforderlich", http.StatusBadRequest)
		return
	}

	// Prüfe Berechtigung: READ_WRITE oder FULL_ACCESS erforderlich zum Erstellen von FQDNs
	userID, username := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasPermission, err := hasPermission(userID, spaceID, PermissionReadWrite)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasPermission {
		http.Error(w, "Keine Berechtigung zum Erstellen von FQDNs. Lesen/Schreiben oder Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	// Prüfe ob der Space existiert
	var exists bool
	err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM spaces WHERE id = ?)", spaceID).Scan(&exists)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen des Space", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen des Space: %v", err)
		return
	}

	if !exists {
		http.Error(w, "Space nicht gefunden", http.StatusNotFound)
		return
	}

	var req CreateFQDNRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	if req.FQDN == "" {
		http.Error(w, "FQDN is required", http.StatusBadRequest)
		return
	}

	// Prüfe ob der FQDN bereits existiert (case-insensitive)
	var fqdnExists bool
	err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM fqdns WHERE LOWER(fqdn) = LOWER(?))", req.FQDN).Scan(&fqdnExists)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen des FQDN", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen des FQDN: %v", err)
		return
	}

	if fqdnExists {
		http.Error(w, "Dieser FQDN existiert bereits", http.StatusConflict)
		return
	}

	// Generiere eindeutige UUID
	id := uuid.New().String()
	createdAt := time.Now()

	// Speichere in Datenbank
	_, err = db.Exec(
		"INSERT INTO fqdns (id, space_id, fqdn, description, created_at) VALUES (?, ?, ?, ?, ?)",
		id, spaceID, req.FQDN, req.Description, createdAt,
	)
	if err != nil {
		http.Error(w, "Fehler beim Speichern des FQDN", http.StatusInternalServerError)
		log.Printf("Fehler beim Speichern des FQDN: %v", err)
		return
	}

	newFqdn := FQDN{
		ID:          id,
		SpaceID:     spaceID,
		FQDN:        req.FQDN,
		Description: req.Description,
		CreatedAt:   createdAt.Format(time.RFC3339),
	}

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(newFqdn)

	// Audit-Log: FQDN erstellt
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "CREATE", "fqdn", id, userID, username, map[string]interface{}{
		"fqdn":        req.FQDN,
		"spaceId":     spaceID,
		"description": req.Description,
		"message":     fmt.Sprintf("FQDN erstellt: %s (Space: %s)", req.FQDN, spaceID),
	}, ipAddress, userAgent)
}

func deleteFqdnHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "DELETE, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["id"]
	fqdnID := vars["fqdnId"]

	if spaceID == "" || fqdnID == "" {
		http.Error(w, "Space ID und FQDN ID sind erforderlich", http.StatusBadRequest)
		return
	}

	// Prüfe Berechtigung: Nur FULL_ACCESS darf FQDNs löschen
	userID, username := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasPermission, err := hasPermission(userID, spaceID, PermissionFullAccess)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasPermission {
		http.Error(w, "Keine Berechtigung zum Löschen von FQDNs. Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	// Prüfe ob der FQDN existiert und zum Space gehört
	var exists bool
	err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM fqdns WHERE id = ? AND space_id = ?)", fqdnID, spaceID).Scan(&exists)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen des FQDN", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen des FQDN: %v", err)
		return
	}

	if !exists {
		http.Error(w, "FQDN nicht gefunden", http.StatusNotFound)
		return
	}

	// Beginne Transaktion für atomares Löschen
	tx, err := db.Begin()
	if err != nil {
		http.Error(w, "Fehler beim Starten der Transaktion", http.StatusInternalServerError)
		log.Printf("Fehler beim Starten der Transaktion: %v", err)
		return
	}
	defer tx.Rollback()

	// Lösche zuerst alle CSRs für diesen FQDN (falls CASCADE nicht funktioniert)
	_, err = tx.Exec("DELETE FROM csrs WHERE fqdn_id = ? AND space_id = ?", fqdnID, spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Löschen der CSRs", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen der CSRs: %v", err)
		return
	}

	// Lösche den FQDN
	result, err := tx.Exec("DELETE FROM fqdns WHERE id = ? AND space_id = ?", fqdnID, spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Löschen des FQDN", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen des FQDN: %v", err)
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		tx.Rollback()
		http.Error(w, "Fehler beim Prüfen der gelöschten Zeilen", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der gelöschten Zeilen: %v", err)
		return
	}

	if rowsAffected == 0 {
		tx.Rollback()
		http.Error(w, "FQDN nicht gefunden", http.StatusNotFound)
		return
	}

	// Committe die Transaktion
	err = tx.Commit()
	if err != nil {
		http.Error(w, "Fehler beim Speichern der Änderungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Committen der Transaktion: %v", err)
		return
	}

	log.Printf("FQDN %s und zugehörige CSRs erfolgreich gelöscht", fqdnID)
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{"message": "FQDN erfolgreich gelöscht"})

	// Audit-Log: FQDN gelöscht
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "DELETE", "fqdn", fqdnID, userID, username, map[string]interface{}{
		"spaceId": spaceID,
		"message": fmt.Sprintf("FQDN gelöscht (Space: %s)", spaceID),
	}, ipAddress, userAgent)
}

func deleteAllFqdnsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "DELETE, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["id"]

	if spaceID == "" {
		http.Error(w, "Space ID ist erforderlich", http.StatusBadRequest)
		return
	}

	// Prüfe Berechtigung: Nur FULL_ACCESS darf alle FQDNs eines Spaces löschen
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasPermission, err := hasPermission(userID, spaceID, PermissionFullAccess)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasPermission {
		http.Error(w, "Keine Berechtigung zum Löschen aller FQDNs. Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	// Prüfe ob der Space existiert
	var exists bool
	err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM spaces WHERE id = ?)", spaceID).Scan(&exists)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen des Space", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen des Space: %v", err)
		return
	}

	if !exists {
		http.Error(w, "Space nicht gefunden", http.StatusNotFound)
		return
	}

	// Beginne Transaktion für atomares Löschen
	tx, err := db.Begin()
	if err != nil {
		http.Error(w, "Fehler beim Starten der Transaktion", http.StatusInternalServerError)
		log.Printf("Fehler beim Starten der Transaktion: %v", err)
		return
	}
	defer tx.Rollback()

	// Lösche zuerst alle CSRs für alle FQDNs dieses Spaces
	_, err = tx.Exec("DELETE FROM csrs WHERE space_id = ?", spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Löschen der CSRs", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen der CSRs: %v", err)
		return
	}

	// Lösche alle FQDNs des Spaces
	result, err := tx.Exec("DELETE FROM fqdns WHERE space_id = ?", spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Löschen der FQDNs", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen der FQDNs: %v", err)
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		tx.Rollback()
		http.Error(w, "Fehler beim Prüfen der gelöschten Zeilen", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der gelöschten Zeilen: %v", err)
		return
	}

	// Committe die Transaktion
	err = tx.Commit()
	if err != nil {
		http.Error(w, "Fehler beim Speichern der Änderungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Committen der Transaktion: %v", err)
		return
	}

	log.Printf("Gelöscht: %d FQDNs und zugehörige CSRs aus Space %s", rowsAffected, spaceID)
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message":      "Alle FQDNs und zugehörige CSRs erfolgreich gelöscht",
		"deletedCount": rowsAffected,
	})
}

func deleteAllFqdnsGlobalHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "DELETE, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Prüfe Berechtigung: Nur FULL_ACCESS darf alle FQDNs global löschen
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	// Prüfe ob User Admin ist - Admins haben immer Vollzugriff
	isAdmin, err := isUserAdmin(userID)
	if err != nil {
		log.Printf("Fehler beim Prüfen des Admin-Status: %v", err)
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		return
	}

	permissions, err := getUserPermissions(userID)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Berechtigungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Berechtigungen: %v", err)
		return
	}

	// Admin oder HasFullAccess erlaubt Löschen aller FQDNs
	hasFullAccess := isAdmin || permissions.HasFullAccess

	// Wenn nicht Admin, prüfe auch Gruppen
	if !isAdmin && len(permissions.Groups) > 0 {
		for _, group := range permissions.Groups {
			if group.Permission == PermissionFullAccess {
				hasFullAccess = true
				break
			}
		}
	}

	if !hasFullAccess {
		http.Error(w, "Keine Berechtigung zum Löschen aller FQDNs. Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	// Prüfe Query-Parameter für Bestätigung (Sicherheitsmaßnahme)
	confirm := r.URL.Query().Get("confirm")
	if confirm != "true" {
		http.Error(w, "Bestätigung erforderlich. Verwenden Sie ?confirm=true", http.StatusBadRequest)
		return
	}

	// Zähle zuerst die Anzahl der FQDNs
	var totalCount int
	err = db.QueryRow("SELECT COUNT(*) FROM fqdns").Scan(&totalCount)
	if err != nil {
		http.Error(w, "Fehler beim Zählen der FQDNs", http.StatusInternalServerError)
		log.Printf("Fehler beim Zählen der FQDNs: %v", err)
		return
	}

	if totalCount == 0 {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"message":      "Keine FQDNs zum Löschen vorhanden",
			"deletedCount": 0,
		})
		return
	}

	// Beginne Transaktion für atomares Löschen
	tx, err := db.Begin()
	if err != nil {
		http.Error(w, "Fehler beim Starten der Transaktion", http.StatusInternalServerError)
		log.Printf("Fehler beim Starten der Transaktion: %v", err)
		return
	}
	defer tx.Rollback()

	// Lösche zuerst alle CSRs
	_, err = tx.Exec("DELETE FROM csrs")
	if err != nil {
		http.Error(w, "Fehler beim Löschen aller CSRs", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen aller CSRs: %v", err)
		return
	}

	// Lösche alle FQDNs
	result, err := tx.Exec("DELETE FROM fqdns")
	if err != nil {
		http.Error(w, "Fehler beim Löschen aller FQDNs", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen aller FQDNs: %v", err)
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		tx.Rollback()
		http.Error(w, "Fehler beim Prüfen der gelöschten Zeilen", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der gelöschten Zeilen: %v", err)
		return
	}

	// Committe die Transaktion
	err = tx.Commit()
	if err != nil {
		http.Error(w, "Fehler beim Speichern der Änderungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Committen der Transaktion: %v", err)
		return
	}

	log.Printf("Gelöscht: %d FQDNs und alle zugehörigen CSRs aus allen Spaces", rowsAffected)
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message":      "Alle FQDNs und zugehörige CSRs erfolgreich gelöscht",
		"deletedCount": rowsAffected,
	})
}

func deleteAllCSRsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "DELETE, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Prüfe Berechtigung: Nur FULL_ACCESS darf alle CSRs löschen
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	// Prüfe ob User Admin ist - Admins haben immer Vollzugriff
	isAdmin, err := isUserAdmin(userID)
	if err != nil {
		log.Printf("Fehler beim Prüfen des Admin-Status: %v", err)
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		return
	}

	permissions, err := getUserPermissions(userID)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Berechtigungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Berechtigungen: %v", err)
		return
	}

	// Admin oder HasFullAccess erlaubt Löschen aller CSRs
	hasFullAccess := isAdmin || permissions.HasFullAccess

	// Wenn nicht Admin, prüfe auch Gruppen
	if !isAdmin && len(permissions.Groups) > 0 {
		for _, group := range permissions.Groups {
			if group.Permission == PermissionFullAccess {
				hasFullAccess = true
				break
			}
		}
	}

	if !hasFullAccess {
		http.Error(w, "Keine Berechtigung zum Löschen aller CSRs. Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	// Prüfe Query-Parameter für Bestätigung (Sicherheitsmaßnahme)
	confirm := r.URL.Query().Get("confirm")
	if confirm != "true" {
		http.Error(w, "Bestätigung erforderlich. Verwenden Sie ?confirm=true", http.StatusBadRequest)
		return
	}

	// Zähle zuerst die Anzahl der CSRs
	var totalCount int
	err = db.QueryRow("SELECT COUNT(*) FROM csrs").Scan(&totalCount)
	if err != nil {
		http.Error(w, "Fehler beim Zählen der CSRs", http.StatusInternalServerError)
		log.Printf("Fehler beim Zählen der CSRs: %v", err)
		return
	}

	if totalCount == 0 {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"message":      "Keine CSRs zum Löschen vorhanden",
			"deletedCount": 0,
		})
		return
	}

	// Beginne Transaktion für atomare Operation
	tx, err := db.Begin()
	if err != nil {
		http.Error(w, "Fehler beim Starten der Transaktion", http.StatusInternalServerError)
		log.Printf("Fehler beim Starten der Transaktion: %v", err)
		return
	}
	defer tx.Rollback()

	// Lösche alle CSRs
	result, err := tx.Exec("DELETE FROM csrs")
	if err != nil {
		http.Error(w, "Fehler beim Löschen aller CSRs", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen aller CSRs: %v", err)
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		tx.Rollback()
		http.Error(w, "Fehler beim Prüfen der gelöschten Zeilen", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der gelöschten Zeilen: %v", err)
		return
	}

	// Committe die Transaktion
	err = tx.Commit()
	if err != nil {
		http.Error(w, "Fehler beim Speichern der Änderungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Committen der Transaktion: %v", err)
		return
	}

	log.Printf("Gelöscht: %d CSRs aus allen Spaces", rowsAffected)
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message":      "Alle CSRs erfolgreich gelöscht",
		"deletedCount": rowsAffected,
	})
}

func uploadCSRHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Parse multipart form
	err := r.ParseMultipartForm(10 << 20) // 10 MB max
	if err != nil {
		http.Error(w, "Fehler beim Parsen des Formulars", http.StatusBadRequest)
		return
	}

	spaceID := r.FormValue("spaceId")
	fqdnName := r.FormValue("fqdn")

	if spaceID == "" || fqdnName == "" {
		http.Error(w, "spaceId und fqdn sind erforderlich", http.StatusBadRequest)
		return
	}

	// Prüfe Berechtigung: READ_WRITE oder FULL_ACCESS erforderlich zum Hochladen von CSRs
	userID, username := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasPermission, err := hasPermission(userID, spaceID, PermissionReadWrite)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasPermission {
		http.Error(w, "Keine Berechtigung zum Hochladen von CSRs. Lesen/Schreiben oder Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	// Prüfe ob Space existiert
	var spaceExists bool
	err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM spaces WHERE id = ?)", spaceID).Scan(&spaceExists)
	if err != nil || !spaceExists {
		http.Error(w, "Space nicht gefunden", http.StatusNotFound)
		return
	}

	// Prüfe ob FQDN existiert und zum Space gehört
	var fqdnID string
	err = db.QueryRow("SELECT id FROM fqdns WHERE fqdn = ? AND space_id = ?", fqdnName, spaceID).Scan(&fqdnID)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "FQDN nicht gefunden oder gehört nicht zu diesem Space", http.StatusNotFound)
		} else {
			http.Error(w, "Fehler beim Prüfen des FQDN", http.StatusInternalServerError)
		}
		return
	}

	// Hole die CSR-Datei
	file, header, err := r.FormFile("csr")
	if err != nil {
		http.Error(w, "Fehler beim Lesen der CSR-Datei", http.StatusBadRequest)
		return
	}
	defer file.Close()

	// Lese den Dateiinhalt
	csrBytes := make([]byte, header.Size)
	_, err = io.ReadFull(file, csrBytes)
	if err != nil {
		http.Error(w, "Fehler beim Lesen der CSR-Datei", http.StatusBadRequest)
		return
	}

	csrPEM := string(csrBytes)

	// Parse CSR
	block, _ := pem.Decode(csrBytes)
	if block == nil {
		http.Error(w, "Ungültiges PEM-Format", http.StatusBadRequest)
		return
	}

	csr, err := x509.ParseCertificateRequest(block.Bytes)
	if err != nil {
		http.Error(w, "Fehler beim Parsen des CSR: "+err.Error(), http.StatusBadRequest)
		return
	}

	// Extrahiere Informationen
	subject := csr.Subject.String()
	publicKeyAlgorithm := csr.PublicKeyAlgorithm.String()
	signatureAlgorithm := csr.SignatureAlgorithm.String()

	// Bestimme Key Size
	keySize := 0
	if csr.PublicKey != nil {
		switch pub := csr.PublicKey.(type) {
		case interface{ Size() int }:
			keySize = pub.Size() * 8 // Convert bytes to bits
		}
	}

	// Extrahiere SANs
	dnsNames := csr.DNSNames
	emailAddresses := csr.EmailAddresses
	ipAddresses := make([]string, len(csr.IPAddresses))
	for i, ip := range csr.IPAddresses {
		ipAddresses[i] = ip.String()
	}
	uris := make([]string, len(csr.URIs))
	for i, uri := range csr.URIs {
		uris[i] = uri.String()
	}

	// Extrahiere Extensions
	extensions := make([]Extension, 0)
	for _, ext := range csr.Extensions {
		oidStr := ext.Id.String()
		name := getExtensionName(oidStr)
		description, purposes := parseExtensionValue(oidStr, ext.Value, csr)

		extension := Extension{
			ID:          ext.Id.String(),
			OID:         oidStr,
			Name:        name,
			Critical:    ext.Critical,
			Value:       hex.EncodeToString(ext.Value),
			Description: description,
			Purposes:    purposes,
		}
		extensions = append(extensions, extension)
	}

	// Konvertiere Slices zu JSON-Strings für DB
	dnsNamesJSON, _ := json.Marshal(dnsNames)
	emailAddressesJSON, _ := json.Marshal(emailAddresses)
	ipAddressesJSON, _ := json.Marshal(ipAddresses)
	urisJSON, _ := json.Marshal(uris)
	extensionsJSON, _ := json.Marshal(extensions)

	// Generiere eindeutige ID
	csrID := uuid.New().String()
	createdAt := time.Now()

	// Speichere in Datenbank
	_, err = db.Exec(`
		INSERT INTO csrs (
			id, fqdn_id, space_id, fqdn, csr_pem, subject, 
			public_key_algorithm, signature_algorithm, key_size,
			dns_names, email_addresses, ip_addresses, uris, extensions, created_at
		) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
		csrID, fqdnID, spaceID, fqdnName, csrPEM, subject,
		publicKeyAlgorithm, signatureAlgorithm, keySize,
		string(dnsNamesJSON), string(emailAddressesJSON), string(ipAddressesJSON), string(urisJSON), string(extensionsJSON), createdAt,
	)
	if err != nil {
		http.Error(w, "Fehler beim Speichern des CSR", http.StatusInternalServerError)
		log.Printf("Fehler beim Speichern des CSR: %v", err)
		return
	}

	newCSR := CSR{
		ID:                 csrID,
		FQDNID:             fqdnID,
		SpaceID:            spaceID,
		FQDN:               fqdnName,
		CSRPEM:             csrPEM,
		Subject:            subject,
		PublicKeyAlgorithm: publicKeyAlgorithm,
		SignatureAlgorithm: signatureAlgorithm,
		KeySize:            keySize,
		DNSNames:           dnsNames,
		EmailAddresses:     emailAddresses,
		IPAddresses:        ipAddresses,
		URIs:               uris,
		Extensions:         extensions,
		CreatedAt:          createdAt.Format(time.RFC3339),
	}

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(newCSR)

	// Audit-Log: CSR hochgeladen
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "UPLOAD", "csr", csrID, userID, username, map[string]interface{}{
		"fqdnId":  fqdnID,
		"spaceId": spaceID,
		"message": fmt.Sprintf("CSR hochgeladen für FQDN: %s (Space: %s)", fqdnID, spaceID),
	}, ipAddress, userAgent)
}

func getCSRByFQDNHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["spaceId"]
	fqdnID := vars["fqdnId"]

	if spaceID == "" || fqdnID == "" {
		http.Error(w, "spaceId und fqdnId sind erforderlich", http.StatusBadRequest)
		return
	}

	// Prüfe Berechtigung: Benutzer muss Zugriff auf den Space haben (READ, READ_WRITE oder FULL_ACCESS)
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasAccess, err := hasSpaceAccess(userID, spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasAccess {
		http.Error(w, "Keine Berechtigung für diesen Space", http.StatusForbidden)
		return
	}

	// Prüfe ob nur der neueste CSR gewünscht ist
	latestOnly := r.URL.Query().Get("latest") == "true"

	if latestOnly {
		// Hole nur den neuesten CSR
		var csr CSR
		var createdAt time.Time
		var dnsNamesJSON, emailAddressesJSON, ipAddressesJSON, urisJSON, extensionsJSON sql.NullString

		err := db.QueryRow(`
			SELECT id, fqdn_id, space_id, fqdn, csr_pem, subject,
			       public_key_algorithm, signature_algorithm, key_size,
			       dns_names, email_addresses, ip_addresses, uris, extensions, created_at
			FROM csrs
			WHERE fqdn_id = ? AND space_id = ?
			ORDER BY created_at DESC
			LIMIT 1
		`, fqdnID, spaceID).Scan(
			&csr.ID, &csr.FQDNID, &csr.SpaceID, &csr.FQDN, &csr.CSRPEM, &csr.Subject,
			&csr.PublicKeyAlgorithm, &csr.SignatureAlgorithm, &csr.KeySize,
			&dnsNamesJSON, &emailAddressesJSON, &ipAddressesJSON, &urisJSON, &extensionsJSON, &createdAt,
		)

		if err != nil {
			if err == sql.ErrNoRows {
				w.WriteHeader(http.StatusOK)
				json.NewEncoder(w).Encode(nil)
				return
			}
			http.Error(w, "Fehler beim Abrufen des CSR", http.StatusInternalServerError)
			log.Printf("Fehler beim Abrufen des CSR: %v", err)
			return
		}

		// Parse JSON-Strings zurück zu Slices
		json.Unmarshal([]byte(dnsNamesJSON.String), &csr.DNSNames)
		json.Unmarshal([]byte(emailAddressesJSON.String), &csr.EmailAddresses)
		json.Unmarshal([]byte(ipAddressesJSON.String), &csr.IPAddresses)
		json.Unmarshal([]byte(urisJSON.String), &csr.URIs)
		if extensionsJSON.Valid {
			json.Unmarshal([]byte(extensionsJSON.String), &csr.Extensions)
		} else {
			csr.Extensions = []Extension{}
		}
		csr.CreatedAt = createdAt.Format(time.RFC3339)

		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(csr)
	} else {
		// Hole alle CSRs für diesen FQDN
		rows, err := db.Query(`
			SELECT id, fqdn_id, space_id, fqdn, csr_pem, subject,
			       public_key_algorithm, signature_algorithm, key_size,
			       dns_names, email_addresses, ip_addresses, uris, extensions, created_at
			FROM csrs
			WHERE fqdn_id = ? AND space_id = ?
			ORDER BY created_at DESC
		`, fqdnID, spaceID)

		if err != nil {
			http.Error(w, "Fehler beim Abrufen der CSRs", http.StatusInternalServerError)
			log.Printf("Fehler beim Abrufen der CSRs: %v", err)
			return
		}
		defer rows.Close()

		var csrs []CSR
		for rows.Next() {
			var csr CSR
			var createdAt time.Time
			var dnsNamesJSON, emailAddressesJSON, ipAddressesJSON, urisJSON string
			var extensionsJSON sql.NullString

			err := rows.Scan(
				&csr.ID, &csr.FQDNID, &csr.SpaceID, &csr.FQDN, &csr.CSRPEM, &csr.Subject,
				&csr.PublicKeyAlgorithm, &csr.SignatureAlgorithm, &csr.KeySize,
				&dnsNamesJSON, &emailAddressesJSON, &ipAddressesJSON, &urisJSON, &extensionsJSON, &createdAt,
			)
			if err != nil {
				http.Error(w, "Fehler beim Lesen der Daten", http.StatusInternalServerError)
				log.Printf("Fehler beim Lesen der Daten: %v", err)
				return
			}

			// Parse JSON-Strings zurück zu Slices
			json.Unmarshal([]byte(dnsNamesJSON), &csr.DNSNames)
			json.Unmarshal([]byte(emailAddressesJSON), &csr.EmailAddresses)
			json.Unmarshal([]byte(ipAddressesJSON), &csr.IPAddresses)
			json.Unmarshal([]byte(urisJSON), &csr.URIs)
			if extensionsJSON.Valid {
				json.Unmarshal([]byte(extensionsJSON.String), &csr.Extensions)
			} else {
				csr.Extensions = []Extension{}
			}
			csr.CreatedAt = createdAt.Format(time.RFC3339)

			csrs = append(csrs, csr)
		}

		if err = rows.Err(); err != nil {
			http.Error(w, "Fehler beim Verarbeiten der Daten", http.StatusInternalServerError)
			log.Printf("Fehler beim Verarbeiten der Daten: %v", err)
			return
		}

		if csrs == nil {
			csrs = []CSR{}
		}

		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(csrs)
	}
}

func swaggerUIHandler(w http.ResponseWriter, r *http.Request) {
	html := `<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <title>Certigo Addon API - Swagger UI</title>
  <link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css" />
  <style>
    html {
      box-sizing: border-box;
      overflow: -moz-scrollbars-vertical;
      overflow-y: scroll;
    }
    *, *:before, *:after {
      box-sizing: inherit;
    }
    body {
      margin:0;
      background: #fafafa;
    }
  </style>
</head>
<body>
  <div id="swagger-ui"></div>
  <script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js"></script>
  <script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-standalone-preset.js"></script>
  <script>
    window.onload = function() {
      const ui = SwaggerUIBundle({
        url: "/api/openapi.yaml",
        dom_id: '#swagger-ui',
        deepLinking: true,
        presets: [
          SwaggerUIBundle.presets.apis,
          SwaggerUIStandalonePreset
        ],
        plugins: [
          SwaggerUIBundle.plugins.DownloadUrl
        ],
        layout: "StandaloneLayout"
      });
    };
  </script>
</body>
</html>`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.Write([]byte(html))
}

func openAPIHandler(w http.ResponseWriter, r *http.Request) {
	// Lese die OpenAPI YAML Datei
	openAPIContent := `openapi: 3.0.3
info:
  title: Certigo Addon API
  description: API für die Verwaltung von Spaces, FQDNs und Certificate Signing Requests (CSRs)
  version: 1.0.0
  contact:
    name: Certigo Addon
servers:
  - url: http://localhost:8080/api
    description: Local development server
paths:
  /health:
    get:
      summary: System Health Check
      description: Prüft den Systemstatus des Backends
      tags: [System]
      responses:
        '200':
          description: System ist erreichbar
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
  /stats:
    get:
      summary: Statistiken abrufen
      description: Ruft Statistiken über die Anzahl der Spaces, FQDNs und CSRs ab
      tags: [System]
      responses:
        '200':
          description: Statistiken erfolgreich abgerufen
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsResponse'
  /spaces:
    get:
      summary: Alle Spaces abrufen
      description: Ruft eine Liste aller Spaces ab
      tags: [Spaces]
      responses:
        '200':
          description: Liste der Spaces
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Space'
    post:
      summary: Space erstellen
      description: Erstellt einen neuen Space
      tags: [Spaces]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSpaceRequest'
      responses:
        '201':
          description: Space erfolgreich erstellt
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Space'
        '400':
          description: Ungültige Anfrage
  /spaces/{id}:
    delete:
      summary: Space löschen
      description: Löscht einen Space. Wenn der Space FQDNs enthält, muss der Parameter deleteFqdns=true gesetzt werden.
      tags: [Spaces]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: deleteFqdns
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Wenn true, werden alle FQDNs des Spaces mitgelöscht
      responses:
        '200':
          description: Space erfolgreich gelöscht
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
        '404':
          description: Space nicht gefunden
        '409':
          description: Space enthält noch FQDNs
  /spaces/{id}/fqdns/count:
    get:
      summary: FQDN-Anzahl abrufen
      description: Ruft die Anzahl der FQDNs für einen Space ab
      tags: [FQDNs]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Anzahl der FQDNs
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CountResponse'
  /spaces/{id}/fqdns:
    get:
      summary: Alle FQDNs eines Spaces abrufen
      description: Ruft alle FQDNs für einen Space ab
      tags: [FQDNs]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Liste der FQDNs
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FQDN'
        '404':
          description: Space nicht gefunden
    post:
      summary: FQDN erstellen
      description: Erstellt einen neuen FQDN innerhalb eines Spaces
      tags: [FQDNs]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFQDNRequest'
      responses:
        '201':
          description: FQDN erfolgreich erstellt
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FQDN'
        '400':
          description: Ungültige Anfrage
        '404':
          description: Space nicht gefunden
        '409':
          description: FQDN existiert bereits in diesem Space
    delete:
      summary: Alle FQDNs eines Spaces löschen
      description: Löscht alle FQDNs eines Spaces
      tags: [FQDNs]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Alle FQDNs erfolgreich gelöscht
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteResponse'
  /spaces/{id}/fqdns/{fqdnId}:
    delete:
      summary: FQDN löschen
      description: Löscht einen einzelnen FQDN
      tags: [FQDNs]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: fqdnId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: FQDN erfolgreich gelöscht
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
        '404':
          description: FQDN nicht gefunden
  /fqdns:
    delete:
      summary: Alle FQDNs global löschen
      description: Löscht alle FQDNs aus allen Spaces. Erfordert confirm=true Query-Parameter.
      tags: [FQDNs]
      parameters:
        - name: confirm
          in: query
          required: true
          schema:
            type: boolean
          description: Muss true sein, um die Operation auszuführen
      responses:
        '200':
          description: Alle FQDNs erfolgreich gelöscht
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteResponse'
        '400':
          description: Bestätigung erforderlich
  /csrs:
    delete:
      summary: Alle CSRs global löschen
      description: Löscht alle CSRs aus allen Spaces. Erfordert confirm=true Query-Parameter.
      tags: [CSRs]
      parameters:
        - name: confirm
          in: query
          required: true
          schema:
            type: string
          description: Muss "true" sein, um die Operation auszuführen
          example: "true"
      responses:
        '200':
          description: Alle CSRs erfolgreich gelöscht
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteResponse'
        '400':
          description: Bestätigung erforderlich
  /spaces/{spaceId}/fqdns/{fqdnId}/csr:
    post:
      summary: CSR hochladen
      description: Lädt einen CSR (Certificate Signing Request) im PEM-Format hoch
      tags: [CSRs]
      parameters:
        - name: spaceId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: fqdnId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [csr, spaceId, fqdn]
              properties:
                csr:
                  type: string
                  format: binary
                  description: CSR-Datei im PEM-Format
                spaceId:
                  type: string
                  description: ID des Spaces
                fqdn:
                  type: string
                  description: Name des FQDNs
      responses:
        '201':
          description: CSR erfolgreich hochgeladen
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CSR'
        '400':
          description: Ungültige Anfrage oder ungültiges CSR-Format
        '404':
          description: Space oder FQDN nicht gefunden
    get:
      summary: CSR(s) abrufen
      description: Ruft CSR(s) für einen FQDN ab. Mit latest=true wird nur der neueste CSR zurückgegeben.
      tags: [CSRs]
      parameters:
        - name: spaceId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: fqdnId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: latest
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Wenn true, wird nur der neueste CSR zurückgegeben
      responses:
        '200':
          description: CSR(s) erfolgreich abgerufen
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/CSR'
                  - type: array
                    items:
                      $ref: '#/components/schemas/CSR'
        '404':
          description: FQDN nicht gefunden
components:
  schemas:
    HealthResponse:
      type: object
      properties:
        status:
          type: string
          example: "ok"
        message:
          type: string
          example: "Backend ist erreichbar"
        time:
          type: string
          format: date-time
          example: "2024-01-15T10:30:00Z"
    StatsResponse:
      type: object
      properties:
        spaces:
          type: integer
          example: 5
        fqdns:
          type: integer
          example: 12
        csrs:
          type: integer
          example: 7
        certificates:
          type: integer
          example: 8
        users:
          type: integer
          example: 3
    Space:
      type: object
      properties:
        id:
          type: string
          format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
        name:
          type: string
          example: "Mein Space"
        description:
          type: string
          example: "Beschreibung des Spaces"
        createdAt:
          type: string
          format: date-time
          example: "2024-01-15T10:30:00Z"
    CreateSpaceRequest:
      type: object
      required: [name]
      properties:
        name:
          type: string
          example: "Mein Space"
        description:
          type: string
          example: "Beschreibung des Spaces"
    FQDN:
      type: object
      properties:
        id:
          type: string
          format: uuid
          example: "660e8400-e29b-41d4-a716-446655440000"
        spaceId:
          type: string
          format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
        fqdn:
          type: string
          example: "example.com"
        description:
          type: string
          example: "Beschreibung des FQDN"
        createdAt:
          type: string
          format: date-time
          example: "2024-01-15T10:30:00Z"
    CreateFQDNRequest:
      type: object
      required: [fqdn]
      properties:
        fqdn:
          type: string
          example: "example.com"
        description:
          type: string
          example: "Beschreibung des FQDN"
    Extension:
      type: object
      properties:
        id:
          type: string
          example: "2.5.29.37"
        oid:
          type: string
          example: "2.5.29.37"
        name:
          type: string
          example: "X509v3 Extended Key Usage"
        critical:
          type: boolean
          example: false
        value:
          type: string
          example: "301406082b0601050507030106082b06010505070302"
        description:
          type: string
          example: "TLS Web Server Authentication"
        purposes:
          type: array
          items:
            type: string
          example: ["TLS Web Server Authentication", "TLS Web Client Authentication"]
    CSR:
      type: object
      properties:
        id:
          type: string
          format: uuid
          example: "770e8400-e29b-41d4-a716-446655440000"
        fqdnId:
          type: string
          format: uuid
          example: "660e8400-e29b-41d4-a716-446655440000"
        spaceId:
          type: string
          format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
        fqdn:
          type: string
          example: "example.com"
        csrPem:
          type: string
          example: "-----BEGIN CERTIFICATE REQUEST-----"
        subject:
          type: string
          example: "CN=example.com"
        publicKeyAlgorithm:
          type: string
          example: "RSA"
        signatureAlgorithm:
          type: string
          example: "SHA256-RSA"
        keySize:
          type: integer
          example: 2048
        dnsNames:
          type: array
          items:
            type: string
          example: ["example.com", "www.example.com"]
        emailAddresses:
          type: array
          items:
            type: string
          example: ["admin@example.com"]
        ipAddresses:
          type: array
          items:
            type: string
          example: ["192.168.1.1"]
        uris:
          type: array
          items:
            type: string
          example: ["https://example.com"]
        extensions:
          type: array
          items:
            $ref: '#/components/schemas/Extension'
        createdAt:
          type: string
          format: date-time
          example: "2024-01-15T10:30:00Z"
    MessageResponse:
      type: object
      properties:
        message:
          type: string
          example: "Operation erfolgreich"
    CountResponse:
      type: object
      properties:
        count:
          type: integer
          example: 5
    DeleteResponse:
      type: object
      properties:
        message:
          type: string
          example: "Alle FQDNs erfolgreich gelöscht"
        deletedCount:
          type: integer
          example: 5`
	w.Header().Set("Content-Type", "application/x-yaml")
	w.Write([]byte(openAPIContent))
}

// User Handler Functions

func getUserPermissionsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Hole Benutzer-ID
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	// Prüfe ob User Admin ist
	isAdmin, err := isUserAdmin(userID)
	if err != nil {
		log.Printf("Fehler beim Prüfen des Admin-Status: %v", err)
		isAdmin = false
	}

	// Hole Berechtigungen
	permissions, err := getUserPermissions(userID)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Berechtigungen", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Berechtigungen: %v", err)
		return
	}

	// Erstelle vereinfachte Antwort für Frontend
	canCreateFqdn := make(map[string]bool)
	canDeleteFqdn := make(map[string]bool)
	canUploadCSR := make(map[string]bool)
	canSignCSR := make(map[string]bool)

	response := map[string]interface{}{
		"userId":           userID,
		"isAdmin":          isAdmin,
		"hasFullAccess":    permissions.HasFullAccess || isAdmin,
		"accessibleSpaces": []string{},
		"permissions": map[string]interface{}{
			"canCreateSpace": permissions.HasFullAccess || isAdmin,
			"canDeleteSpace": permissions.HasFullAccess || isAdmin,
			"canCreateFqdn":  canCreateFqdn,
			"canDeleteFqdn":  canDeleteFqdn,
			"canUploadCSR":   canUploadCSR,
			"canSignCSR":     canSignCSR,
		},
	}

	// Hole alle Spaces
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	spaceRows, err := db.QueryContext(ctx, "SELECT id FROM spaces")
	if err == nil {
		defer spaceRows.Close()
		var allSpaceIDs []string
		for spaceRows.Next() {
			var spaceID string
			if err := spaceRows.Scan(&spaceID); err == nil {
				allSpaceIDs = append(allSpaceIDs, spaceID)
			}
		}
		spaceRows.Close()

		// Prüfe für jeden Space die Berechtigungen
		accessibleSpaces := []string{}

		for _, spaceID := range allSpaceIDs {
			hasAccess, _ := hasSpaceAccess(userID, spaceID)
			if hasAccess {
				accessibleSpaces = append(accessibleSpaces, spaceID)

				// Prüfe READ_WRITE für FQDN erstellen und CSR upload/sign
				hasReadWrite, _ := hasPermission(userID, spaceID, PermissionReadWrite)
				canCreateFqdn[spaceID] = hasReadWrite
				canUploadCSR[spaceID] = hasReadWrite
				canSignCSR[spaceID] = hasReadWrite

				// Prüfe FULL_ACCESS für FQDN löschen
				hasFullAccess, _ := hasPermission(userID, spaceID, PermissionFullAccess)
				canDeleteFqdn[spaceID] = hasFullAccess
			}
		}

		response["accessibleSpaces"] = accessibleSpaces
		perms := response["permissions"].(map[string]interface{})
		perms["canCreateFqdn"] = canCreateFqdn
		perms["canDeleteFqdn"] = canDeleteFqdn
		perms["canUploadCSR"] = canUploadCSR
		perms["canSignCSR"] = canSignCSR
	}

	// Prüfe globale Berechtigungen (Space erstellen/löschen)
	// Admins haben immer Vollzugriff
	if isAdmin {
		perms := response["permissions"].(map[string]interface{})
		perms["canCreateSpace"] = true
		perms["canDeleteSpace"] = true
		// Alle Spaces sind zugänglich für Admins
		spaceRows, err := db.QueryContext(ctx, "SELECT id FROM spaces")
		if err == nil {
			defer spaceRows.Close()
			var allSpaceIDs []string
			for spaceRows.Next() {
				var spaceID string
				if err := spaceRows.Scan(&spaceID); err == nil {
					allSpaceIDs = append(allSpaceIDs, spaceID)
					canCreateFqdn[spaceID] = true
					canDeleteFqdn[spaceID] = true
					canUploadCSR[spaceID] = true
					canSignCSR[spaceID] = true
				}
			}
			spaceRows.Close()
			response["accessibleSpaces"] = allSpaceIDs
			perms["canCreateFqdn"] = canCreateFqdn
			perms["canDeleteFqdn"] = canDeleteFqdn
			perms["canUploadCSR"] = canUploadCSR
			perms["canSignCSR"] = canSignCSR
		}
	} else {
		hasFullAccessGlobal := false
		for _, group := range permissions.Groups {
			if group.Permission == PermissionFullAccess {
				hasFullAccessGlobal = true
				break
			}
		}

		perms := response["permissions"].(map[string]interface{})
		perms["canCreateSpace"] = hasFullAccessGlobal
		perms["canDeleteSpace"] = hasFullAccessGlobal
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

func getUsersHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	// Lade alle Benutzer
	rows, err := db.QueryContext(ctx, "SELECT id, username, email, is_admin, enabled, created_at FROM users ORDER BY created_at DESC")
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Benutzer", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Benutzer: %v", err)
		return
	}
	defer rows.Close()

	var users []User
	var userIDs []string
	for rows.Next() {
		var user User
		var isAdmin, enabled int
		err := rows.Scan(&user.ID, &user.Username, &user.Email, &isAdmin, &enabled, &user.CreatedAt)
		if err != nil {
			http.Error(w, "Fehler beim Lesen der Benutzerdaten", http.StatusInternalServerError)
			log.Printf("Fehler beim Lesen der Benutzerdaten: %v", err)
			return
		}
		user.IsAdmin = isAdmin == 1
		user.Enabled = enabled == 1
		user.GroupIDs = []string{} // Initialisiere als leeres Array
		users = append(users, user)
		userIDs = append(userIDs, user.ID)
	}
	rows.Close()

	// Lade alle Gruppen-Zuweisungen in einem einzigen Query
	if len(userIDs) > 0 {
		// Erstelle Platzhalter für IN-Clause
		placeholders := make([]string, len(userIDs))
		args := make([]interface{}, len(userIDs))
		for i, id := range userIDs {
			placeholders[i] = "?"
			args[i] = id
		}

		query := fmt.Sprintf("SELECT user_id, group_id FROM user_groups WHERE user_id IN (%s)", strings.Join(placeholders, ","))
		groupRows, err := db.QueryContext(ctx, query, args...)
		if err == nil {
			// Erstelle eine Map von user_id zu group_ids
			groupMap := make(map[string][]string)
			for groupRows.Next() {
				var userID, groupID string
				if err := groupRows.Scan(&userID, &groupID); err == nil {
					groupMap[userID] = append(groupMap[userID], groupID)
				}
			}
			groupRows.Close()

			// Weise Gruppen-IDs den Benutzern zu
			for i := range users {
				if groupIDs, exists := groupMap[users[i].ID]; exists {
					users[i].GroupIDs = groupIDs
				}
			}
		}
	}

	json.NewEncoder(w).Encode(users)
}

func getUserHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	userID := vars["id"]

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	var user User
	var isAdmin, enabled int
	err := db.QueryRowContext(ctx, "SELECT id, username, email, is_admin, enabled, created_at FROM users WHERE id = ?", userID).
		Scan(&user.ID, &user.Username, &user.Email, &isAdmin, &enabled, &user.CreatedAt)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Benutzer nicht gefunden", http.StatusNotFound)
			return
		}
		http.Error(w, "Fehler beim Abrufen des Benutzers", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen des Benutzers: %v", err)
		return
	}
	user.IsAdmin = isAdmin == 1
	user.Enabled = enabled == 1

	// Lade Gruppen-IDs für diesen Benutzer
	groupRows, err := db.QueryContext(ctx, "SELECT group_id FROM user_groups WHERE user_id = ?", userID)
	if err == nil {
		var groupIDs []string
		for groupRows.Next() {
			var groupID string
			if err := groupRows.Scan(&groupID); err == nil {
				groupIDs = append(groupIDs, groupID)
			}
		}
		groupRows.Close()
		user.GroupIDs = groupIDs
	} else {
		user.GroupIDs = []string{} // Initialisiere als leeres Array bei Fehler
	}

	json.NewEncoder(w).Encode(user)
}

func createUserHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	var req CreateUserRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Ungültige Anfrage", http.StatusBadRequest)
		return
	}

	// Validierung
	if req.Username == "" || req.Email == "" || req.Password == "" {
		http.Error(w, "Benutzername, E-Mail und Passwort sind erforderlich", http.StatusBadRequest)
		return
	}

	// Passwortrichtlinie prüfen
	if err := validatePassword(req.Password); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}

	// Passwort hashen
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		http.Error(w, "Fehler beim Hashen des Passworts", http.StatusInternalServerError)
		log.Printf("Fehler beim Hashen des Passworts: %v", err)
		return
	}

	// Erstelle Benutzer
	userID := uuid.New().String()
	createdAt := time.Now().Format(time.RFC3339)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	isAdmin := 0
	if req.IsAdmin {
		isAdmin = 1
	}
	// Admin muss immer enabled sein
	enabledValue := 1
	if req.IsAdmin {
		enabledValue = 1 // Admin immer enabled
	}
	_, err = db.ExecContext(ctx,
		"INSERT INTO users (id, username, email, password_hash, is_admin, enabled, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
		userID, req.Username, req.Email, string(hashedPassword), isAdmin, enabledValue, createdAt)
	if err != nil {
		if strings.Contains(err.Error(), "UNIQUE constraint failed") {
			if strings.Contains(err.Error(), "username") {
				http.Error(w, "Benutzername bereits vergeben", http.StatusConflict)
			} else {
				http.Error(w, "E-Mail-Adresse bereits vergeben", http.StatusConflict)
			}
			return
		}
		http.Error(w, "Fehler beim Erstellen des Benutzers", http.StatusInternalServerError)
		log.Printf("Fehler beim Erstellen des Benutzers: %v", err)
		return
	}

	// Weise Gruppen zu, falls angegeben
	if len(req.GroupIDs) > 0 {
		for _, groupID := range req.GroupIDs {
			// Prüfe ob Gruppe existiert
			var exists bool
			err := db.QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM permission_groups WHERE id = ?)", groupID).Scan(&exists)
			if err == nil && exists {
				_, err = db.ExecContext(ctx, "INSERT OR IGNORE INTO user_groups (user_id, group_id) VALUES (?, ?)", userID, groupID)
				if err != nil {
					log.Printf("Fehler beim Zuweisen der Gruppe %s zum Benutzer: %v", groupID, err)
				}
			}
		}
	}

	user := User{
		ID:        userID,
		Username:  req.Username,
		Email:     req.Email,
		IsAdmin:   req.IsAdmin,
		Enabled:   true,
		CreatedAt: createdAt,
		GroupIDs:  req.GroupIDs,
	}

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(user)

	// Audit-Log: User erstellt
	requestUserID, requestUsername := getUserFromRequest(r)
	ipAddress, userAgent := getRequestInfo(r)
	auditDetails := map[string]interface{}{
		"username": req.Username,
		"email":    req.Email,
		"groupIds": req.GroupIDs,
		"message":  fmt.Sprintf("User erstellt: %s (%s)", req.Username, req.Email),
	}
	if req.IsAdmin {
		auditDetails["isAdmin"] = true
		auditDetails["message"] = fmt.Sprintf("Administrator erstellt: %s (%s)", req.Username, req.Email)
	}
	auditService.Track(r.Context(), "CREATE", "user", userID, requestUserID, requestUsername, auditDetails, ipAddress, userAgent)
}

func updateUserHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "PUT, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	userID := vars["id"]

	var req UpdateUserRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Ungültige Anfrage", http.StatusBadRequest)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	// Prüfe ob Benutzer existiert
	var isAdmin int
	var currentUsername, currentEmail string
	err := db.QueryRowContext(ctx, "SELECT is_admin, username, email FROM users WHERE id = ?", userID).
		Scan(&isAdmin, &currentUsername, &currentEmail)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Benutzer nicht gefunden", http.StatusNotFound)
			return
		}
		http.Error(w, "Fehler beim Abrufen des Benutzers", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen des Benutzers: %v", err)
		return
	}

	// Nur der spezielle Admin-User mit UID "admin": Username und Email sind unveränderbar
	// Andere Admin-User können ihre Daten ändern
	if userID == "admin" {
		if req.Username != "" && req.Username != currentUsername {
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(map[string]string{"error": "Der Benutzername des Admin-Users mit UID 'admin' kann nicht geändert werden"})
			return
		}
		if req.Email != "" && req.Email != currentEmail {
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(map[string]string{"error": "Die E-Mail-Adresse des Admin-Users mit UID 'admin' kann nicht geändert werden"})
			return
		}
	}

	// Update Felder
	updates := []string{}
	args := []interface{}{}

	// Nur Username/Email updaten wenn nicht der spezielle Admin-User mit UID "admin"
	// Andere Admin-User können ihre Daten ändern
	if req.Username != "" && (userID != "admin" || req.Username == currentUsername) {
		updates = append(updates, "username = ?")
		args = append(args, req.Username)
	}
	if req.Email != "" && (userID != "admin" || req.Email == currentEmail) {
		updates = append(updates, "email = ?")
		args = append(args, req.Email)
	}

	// isAdmin aktualisieren, falls angegeben
	// UID 'admin' kann seinen Admin-Status nicht ändern
	if req.IsAdmin != nil {
		// UID 'admin' ist immer Admin und kann nicht geändert werden
		if userID == "admin" {
			w.WriteHeader(http.StatusForbidden)
			json.NewEncoder(w).Encode(map[string]string{"error": "Der Admin-Status des Users mit UID 'admin' kann nicht geändert werden"})
			return
		}

		adminValue := 0
		if *req.IsAdmin {
			adminValue = 1
		}
		updates = append(updates, "is_admin = ?")
		args = append(args, adminValue)

		// Wenn Admin aktiviert wird, entferne alle Gruppen-Zuweisungen
		if *req.IsAdmin {
			_, err = db.ExecContext(ctx, "DELETE FROM user_groups WHERE user_id = ?", userID)
			if err != nil {
				log.Printf("Fehler beim Löschen der Gruppen-Zuweisungen für Admin: %v", err)
			}
		}
	}

	// enabled aktualisieren, falls angegeben
	// Nur der spezielle Admin-User mit UID "admin" kann enabled geändert werden
	if req.Enabled != nil {
		// Nur UID "admin" kann enabled geändert werden
		if userID != "admin" {
			w.WriteHeader(http.StatusForbidden)
			json.NewEncoder(w).Encode(map[string]string{"error": "Nur der Admin-User mit UID 'admin' kann aktiviert/deaktiviert werden"})
			return
		}

		// Prüfe ob der anfragende User ein Admin ist (für Deaktivierung)
		if !*req.Enabled {
			requestUserID, _ := getUserFromRequest(r)
			isRequestingAdmin, err := isUserAdmin(requestUserID)
			if err != nil || !isRequestingAdmin {
				w.WriteHeader(http.StatusForbidden)
				json.NewEncoder(w).Encode(map[string]string{"error": "Nur Administratoren können den Admin-User mit UID 'admin' deaktivieren"})
				return
			}
		}

		enabledValue := 0
		if *req.Enabled {
			enabledValue = 1
		}
		updates = append(updates, "enabled = ?")
		args = append(args, enabledValue)
	}

	if req.Password != "" {
		// Altes Passwort ist erforderlich, wenn Passwort geändert wird
		if req.OldPassword == "" {
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(map[string]string{"error": "Altes Passwort ist erforderlich, um das Passwort zu ändern"})
			return
		}

		// Hole aktuelles Passwort-Hash aus der Datenbank
		var storedHash string
		err = db.QueryRowContext(ctx, "SELECT password_hash FROM users WHERE id = ?", userID).Scan(&storedHash)
		if err != nil {
			http.Error(w, "Fehler beim Abrufen des Benutzers", http.StatusInternalServerError)
			log.Printf("Fehler beim Abrufen des Benutzers: %v", err)
			return
		}

		// Validiere altes Passwort
		err = bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(req.OldPassword))
		if err != nil {
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(map[string]string{"error": "Altes Passwort ist falsch"})
			return
		}

		// Passwortrichtlinie prüfen
		if err := validatePassword(req.Password); err != nil {
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
			return
		}

		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
		if err != nil {
			http.Error(w, "Fehler beim Hashen des Passworts", http.StatusInternalServerError)
			log.Printf("Fehler beim Hashen des Passworts: %v", err)
			return
		}
		updates = append(updates, "password_hash = ?")
		args = append(args, string(hashedPassword))
	}

	if len(updates) == 0 {
		http.Error(w, "Keine Felder zum Aktualisieren", http.StatusBadRequest)
		return
	}

	args = append(args, userID)
	query := fmt.Sprintf("UPDATE users SET %s WHERE id = ?", strings.Join(updates, ", "))

	_, err = db.ExecContext(ctx, query, args...)
	if err != nil {
		if strings.Contains(err.Error(), "UNIQUE constraint failed") {
			if strings.Contains(err.Error(), "username") {
				http.Error(w, "Benutzername bereits vergeben", http.StatusConflict)
			} else {
				http.Error(w, "E-Mail-Adresse bereits vergeben", http.StatusConflict)
			}
			return
		}
		http.Error(w, "Fehler beim Aktualisieren des Benutzers", http.StatusInternalServerError)
		log.Printf("Fehler beim Aktualisieren des Benutzers: %v", err)
		return
	}

	// Aktualisiere Gruppen-Zuweisungen, falls angegeben
	// Nur wenn User nicht Admin ist oder Admin deaktiviert wird
	if req.GroupIDs != nil {
		// Prüfe ob User nach Update Admin ist
		var willBeAdmin int
		if req.IsAdmin != nil {
			if *req.IsAdmin {
				willBeAdmin = 1
			}
		} else {
			willBeAdmin = isAdmin
		}

		// Nur Gruppen zuweisen wenn User nicht Admin ist
		if willBeAdmin == 0 {
			// Lösche alle bestehenden Gruppen-Zuweisungen
			_, err = db.ExecContext(ctx, "DELETE FROM user_groups WHERE user_id = ?", userID)
			if err != nil {
				log.Printf("Fehler beim Löschen der Gruppen-Zuweisungen: %v", err)
			}

			// Füge neue Gruppen-Zuweisungen hinzu
			for _, groupID := range req.GroupIDs {
				// Prüfe ob Gruppe existiert
				var exists bool
				err := db.QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM permission_groups WHERE id = ?)", groupID).Scan(&exists)
				if err == nil && exists {
					_, err = db.ExecContext(ctx, "INSERT INTO user_groups (user_id, group_id) VALUES (?, ?)", userID, groupID)
					if err != nil {
						log.Printf("Fehler beim Zuweisen der Gruppe %s zum Benutzer: %v", groupID, err)
					}
				}
			}
		}
	}

	// Lade aktualisierten Benutzer
	var user User
	var isAdminUpdated, enabledUpdated int
	err = db.QueryRowContext(ctx, "SELECT id, username, email, is_admin, enabled, created_at FROM users WHERE id = ?", userID).
		Scan(&user.ID, &user.Username, &user.Email, &isAdminUpdated, &enabledUpdated, &user.CreatedAt)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen des aktualisierten Benutzers", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen des aktualisierten Benutzers: %v", err)
		return
	}
	user.IsAdmin = isAdminUpdated == 1
	user.Enabled = enabledUpdated == 1

	// Lade Gruppen-IDs (nur wenn nicht Admin)
	if user.IsAdmin {
		user.GroupIDs = []string{} // Admins haben keine Gruppen
	} else if req.GroupIDs != nil {
		user.GroupIDs = req.GroupIDs
	} else {
		groupRows, err := db.QueryContext(ctx, "SELECT group_id FROM user_groups WHERE user_id = ?", userID)
		if err == nil {
			var groupIDs []string
			for groupRows.Next() {
				var groupID string
				if err := groupRows.Scan(&groupID); err == nil {
					groupIDs = append(groupIDs, groupID)
				}
			}
			groupRows.Close()
			user.GroupIDs = groupIDs
		} else {
			user.GroupIDs = []string{}
		}
	}

	json.NewEncoder(w).Encode(user)

	// Audit-Log: User aktualisiert
	requestUserID, requestUsername := getUserFromRequest(r)
	ipAddress, userAgent := getRequestInfo(r)
	details := map[string]interface{}{}
	if req.Username != "" {
		details["username"] = req.Username
	}
	if req.Email != "" {
		details["email"] = req.Email
	}
	if req.Password != "" {
		details["passwordChanged"] = true
	}
	if req.IsAdmin != nil {
		details["isAdmin"] = *req.IsAdmin
		if *req.IsAdmin {
			details["message"] = "Benutzer wurde zum Administrator ernannt"
		} else {
			details["message"] = "Administrator-Rechte wurden entfernt"
		}
	}
	if req.Enabled != nil {
		details["enabled"] = *req.Enabled
		if *req.Enabled {
			details["message"] = "Benutzer wurde aktiviert"
		} else {
			details["message"] = "Benutzer wurde deaktiviert"
		}
	}
	if req.GroupIDs != nil {
		details["groupIds"] = req.GroupIDs
	}
	auditService.Track(r.Context(), "UPDATE", "user", vars["id"], requestUserID, requestUsername, details, ipAddress, userAgent)
}

func deleteUserHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "DELETE, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	userID := vars["id"]

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	// Prüfe ob der zu löschende User der spezielle Admin-User mit UID "admin" ist
	// Nur dieser User kann nicht gelöscht werden, andere Admin-User können gelöscht werden
	if userID == "admin" {
		w.WriteHeader(http.StatusForbidden)
		json.NewEncoder(w).Encode(map[string]string{
			"error": "Der Administrator-Benutzer mit UID 'admin' kann nicht gelöscht werden. Verwenden Sie stattdessen die Deaktivierungsfunktion.",
		})
		return
	}

	// Prüfe ob User existiert
	var exists bool
	err := db.QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM users WHERE id = ?)", userID).Scan(&exists)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen des Benutzers", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen des Benutzers: %v", err)
		return
	}
	if !exists {
		http.Error(w, "Benutzer nicht gefunden", http.StatusNotFound)
		return
	}

	result, err := db.ExecContext(ctx, "DELETE FROM users WHERE id = ?", userID)
	if err != nil {
		http.Error(w, "Fehler beim Löschen des Benutzers", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen des Benutzers: %v", err)
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der gelöschten Zeilen", http.StatusInternalServerError)
		return
	}

	if rowsAffected == 0 {
		http.Error(w, "Benutzer nicht gefunden", http.StatusNotFound)
		return
	}

	response := MessageResponse{Message: "Benutzer erfolgreich gelöscht"}
	json.NewEncoder(w).Encode(response)

	// Audit-Log: User gelöscht
	requestUserID, username := getUserFromRequest(r)
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "DELETE", "user", vars["id"], requestUserID, username, map[string]interface{}{
		"message": fmt.Sprintf("User gelöscht: %s", vars["id"]),
	}, ipAddress, userAgent)
}

// Profilbild-Upload Handler
func uploadAvatarHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Prüfe ob Benutzer authentifiziert ist
	userID, username := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	vars := mux.Vars(r)
	requestedUserID := vars["id"]

	// Prüfe ob Benutzer sein eigenes Profilbild hochlädt
	if userID != requestedUserID {
		http.Error(w, "Sie können nur Ihr eigenes Profilbild ändern", http.StatusForbidden)
		return
	}

	// Parse multipart form (max 10MB)
	err := r.ParseMultipartForm(10 << 20) // 10MB
	if err != nil {
		http.Error(w, "Fehler beim Parsen des Formulars", http.StatusBadRequest)
		return
	}

	file, handler, err := r.FormFile("avatar")
	if err != nil {
		http.Error(w, "Keine Datei gefunden", http.StatusBadRequest)
		return
	}
	defer file.Close()

	// Validiere Dateityp (nur Bilder)
	allowedTypes := []string{"image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp"}
	fileType := handler.Header.Get("Content-Type")
	isAllowed := false
	for _, allowedType := range allowedTypes {
		if fileType == allowedType {
			isAllowed = true
			break
		}
	}

	if !isAllowed {
		http.Error(w, "Nur Bilddateien (JPEG, PNG, GIF, WebP) sind erlaubt", http.StatusBadRequest)
		return
	}

	// Bestimme Dateiendung basierend auf Content-Type
	var ext string
	switch fileType {
	case "image/jpeg", "image/jpg":
		ext = ".jpg"
	case "image/png":
		ext = ".png"
	case "image/gif":
		ext = ".gif"
	case "image/webp":
		ext = ".webp"
	default:
		ext = ".jpg"
	}

	// Erstelle Dateiname basierend auf User-ID
	avatarDir := "uploads/avatars"
	filename := userID + ext
	avatarPath := filepath.Join(avatarDir, filename)

	// Lösche alle vorhandenen Avatar-Dateien für diesen Benutzer
	extensions := []string{".jpg", ".jpeg", ".png", ".gif", ".webp"}
	for _, oldExt := range extensions {
		oldPath := filepath.Join(avatarDir, userID+oldExt)
		if _, err := os.Stat(oldPath); err == nil {
			// Datei existiert, lösche sie
			if err := os.Remove(oldPath); err != nil {
				log.Printf("Warnung: Konnte alte Avatar-Datei nicht löschen: %v", err)
				// Weiter machen, auch wenn Löschen fehlschlägt
			} else {
				log.Printf("Alte Avatar-Datei gelöscht: %s", oldPath)
			}
		}
	}

	// Erstelle Datei
	dst, err := os.Create(avatarPath)
	if err != nil {
		http.Error(w, "Fehler beim Erstellen der Datei", http.StatusInternalServerError)
		log.Printf("Fehler beim Erstellen der Avatar-Datei: %v", err)
		return
	}
	defer dst.Close()

	// Kopiere Dateiinhalt
	_, err = io.Copy(dst, file)
	if err != nil {
		http.Error(w, "Fehler beim Speichern der Datei", http.StatusInternalServerError)
		log.Printf("Fehler beim Speichern der Avatar-Datei: %v", err)
		return
	}

	// Audit-Log
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "UPDATE", "user", userID, userID, username, map[string]interface{}{
		"action":   "avatar_uploaded",
		"filename": filename,
	}, ipAddress, userAgent)

	// Erfolgreiche Antwort
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message":  "Profilbild erfolgreich hochgeladen",
		"filename": filename,
		"url":      fmt.Sprintf("/api/users/%s/avatar", userID),
	})
}

// Profilbild-Abruf Handler
func getAvatarHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	userID := vars["id"]

	// Suche nach Avatar-Datei (versuche verschiedene Formate)
	avatarDir := "uploads/avatars"
	extensions := []string{".jpg", ".jpeg", ".png", ".gif", ".webp"}

	var avatarPath string
	var found bool
	for _, ext := range extensions {
		path := filepath.Join(avatarDir, userID+ext)
		if _, err := os.Stat(path); err == nil {
			avatarPath = path
			found = true
			break
		}
	}

	if !found {
		http.Error(w, "Profilbild nicht gefunden", http.StatusNotFound)
		return
	}

	// Öffne Datei
	file, err := os.Open(avatarPath)
	if err != nil {
		http.Error(w, "Fehler beim Öffnen der Datei", http.StatusInternalServerError)
		return
	}
	defer file.Close()

	// Bestimme Content-Type basierend auf Dateiendung
	ext := filepath.Ext(avatarPath)
	var contentType string
	switch ext {
	case ".jpg", ".jpeg":
		contentType = "image/jpeg"
	case ".png":
		contentType = "image/png"
	case ".gif":
		contentType = "image/gif"
	case ".webp":
		contentType = "image/webp"
	default:
		contentType = "image/jpeg"
	}

	w.Header().Set("Content-Type", contentType)
	w.Header().Set("Cache-Control", "public, max-age=3600")
	io.Copy(w, file)
}

// Permission Groups Handler Functions

func getPermissionGroupsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	// Lade alle Gruppen
	rows, err := db.QueryContext(ctx, "SELECT id, name, description, permission, created_at FROM permission_groups ORDER BY created_at DESC")
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Berechtigungsgruppen", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Berechtigungsgruppen: %v", err)
		return
	}
	defer rows.Close()

	var groups []PermissionGroup
	var groupIDs []string
	for rows.Next() {
		var group PermissionGroup
		err := rows.Scan(&group.ID, &group.Name, &group.Description, &group.Permission, &group.CreatedAt)
		if err != nil {
			http.Error(w, "Fehler beim Lesen der Gruppen-Daten", http.StatusInternalServerError)
			log.Printf("Fehler beim Lesen der Gruppen-Daten: %v", err)
			return
		}
		group.SpaceIDs = []string{} // Initialisiere als leeres Array
		groups = append(groups, group)
		groupIDs = append(groupIDs, group.ID)
	}
	rows.Close()

	// Lade alle Space-Zuweisungen in einem einzigen Query
	if len(groupIDs) > 0 {
		// Erstelle Platzhalter für IN-Clause
		placeholders := make([]string, len(groupIDs))
		args := make([]interface{}, len(groupIDs))
		for i, id := range groupIDs {
			placeholders[i] = "?"
			args[i] = id
		}

		query := fmt.Sprintf("SELECT group_id, space_id FROM group_spaces WHERE group_id IN (%s)", strings.Join(placeholders, ","))
		spaceRows, err := db.QueryContext(ctx, query, args...)
		if err == nil {
			// Erstelle eine Map von group_id zu space_ids
			spaceMap := make(map[string][]string)
			for spaceRows.Next() {
				var groupID, spaceID string
				if err := spaceRows.Scan(&groupID, &spaceID); err == nil {
					spaceMap[groupID] = append(spaceMap[groupID], spaceID)
				}
			}
			spaceRows.Close()

			// Weise Space-IDs den Gruppen zu
			for i := range groups {
				if spaceIDs, exists := spaceMap[groups[i].ID]; exists {
					groups[i].SpaceIDs = spaceIDs
				}
			}
		}
	}

	json.NewEncoder(w).Encode(groups)
}

func getPermissionGroupHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	groupID := vars["id"]

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	var group PermissionGroup
	err := db.QueryRowContext(ctx, "SELECT id, name, description, permission, created_at FROM permission_groups WHERE id = ?", groupID).
		Scan(&group.ID, &group.Name, &group.Description, &group.Permission, &group.CreatedAt)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Berechtigungsgruppe nicht gefunden", http.StatusNotFound)
			return
		}
		http.Error(w, "Fehler beim Abrufen der Berechtigungsgruppe", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Berechtigungsgruppe: %v", err)
		return
	}

	// Lade Space-IDs für diese Gruppe
	spaceRows, err := db.QueryContext(ctx, "SELECT space_id FROM group_spaces WHERE group_id = ?", groupID)
	if err == nil {
		var spaceIDs []string
		for spaceRows.Next() {
			var spaceID string
			if err := spaceRows.Scan(&spaceID); err == nil {
				spaceIDs = append(spaceIDs, spaceID)
			}
		}
		spaceRows.Close()
		group.SpaceIDs = spaceIDs
	}

	json.NewEncoder(w).Encode(group)
}

func createPermissionGroupHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	var req CreatePermissionGroupRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Ungültige Anfrage", http.StatusBadRequest)
		return
	}

	// Validierung
	if req.Name == "" {
		http.Error(w, "Name ist erforderlich", http.StatusBadRequest)
		return
	}

	// Validiere Berechtigungsstufe
	if req.Permission != PermissionRead && req.Permission != PermissionReadWrite && req.Permission != PermissionFullAccess {
		http.Error(w, "Ungültige Berechtigungsstufe. Erlaubt: READ, READ_WRITE, FULL_ACCESS", http.StatusBadRequest)
		return
	}

	// Erstelle Gruppe
	groupID := uuid.New().String()
	createdAt := time.Now().Format(time.RFC3339)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	_, err := db.ExecContext(ctx,
		"INSERT INTO permission_groups (id, name, description, permission, created_at) VALUES (?, ?, ?, ?, ?)",
		groupID, req.Name, req.Description, string(req.Permission), createdAt)
	if err != nil {
		if strings.Contains(err.Error(), "UNIQUE constraint failed") {
			http.Error(w, "Gruppenname bereits vergeben", http.StatusConflict)
			return
		}
		http.Error(w, "Fehler beim Erstellen der Berechtigungsgruppe", http.StatusInternalServerError)
		log.Printf("Fehler beim Erstellen der Berechtigungsgruppe: %v", err)
		return
	}

	// Weise Spaces zu, falls angegeben
	if len(req.SpaceIDs) > 0 {
		for _, spaceID := range req.SpaceIDs {
			// Prüfe ob Space existiert
			var exists bool
			err := db.QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM spaces WHERE id = ?)", spaceID).Scan(&exists)
			if err == nil && exists {
				_, err = db.ExecContext(ctx, "INSERT OR IGNORE INTO group_spaces (group_id, space_id) VALUES (?, ?)", groupID, spaceID)
				if err != nil {
					log.Printf("Fehler beim Zuweisen des Space %s zur Gruppe: %v", spaceID, err)
				}
			}
		}
	}

	group := PermissionGroup{
		ID:          groupID,
		Name:        req.Name,
		Description: req.Description,
		Permission:  req.Permission,
		SpaceIDs:    req.SpaceIDs,
		CreatedAt:   createdAt,
	}

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(group)

	// Audit-Log
	requestUserID, requestUsername := getUserFromRequest(r)
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "CREATE", "permission_group", groupID, requestUserID, requestUsername, map[string]interface{}{
		"name":       req.Name,
		"permission": req.Permission,
		"spaceIds":   req.SpaceIDs,
		"message":    fmt.Sprintf("Berechtigungsgruppe erstellt: %s", req.Name),
	}, ipAddress, userAgent)
}

func updatePermissionGroupHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "PUT, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	groupID := vars["id"]

	var req UpdatePermissionGroupRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Ungültige Anfrage", http.StatusBadRequest)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	// Prüfe ob Gruppe existiert
	var exists bool
	err := db.QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM permission_groups WHERE id = ?)", groupID).Scan(&exists)
	if err != nil || !exists {
		http.Error(w, "Berechtigungsgruppe nicht gefunden", http.StatusNotFound)
		return
	}

	// Validiere Berechtigungsstufe, falls angegeben
	if req.Permission != "" {
		if req.Permission != PermissionRead && req.Permission != PermissionReadWrite && req.Permission != PermissionFullAccess {
			http.Error(w, "Ungültige Berechtigungsstufe. Erlaubt: READ, READ_WRITE, FULL_ACCESS", http.StatusBadRequest)
			return
		}
	}

	// Update Felder
	updates := []string{}
	args := []interface{}{}

	if req.Name != "" {
		updates = append(updates, "name = ?")
		args = append(args, req.Name)
	}
	if req.Description != "" {
		updates = append(updates, "description = ?")
		args = append(args, req.Description)
	}
	if req.Permission != "" {
		updates = append(updates, "permission = ?")
		args = append(args, string(req.Permission))
	}

	if len(updates) > 0 {
		args = append(args, groupID)
		query := fmt.Sprintf("UPDATE permission_groups SET %s WHERE id = ?", strings.Join(updates, ", "))
		_, err = db.ExecContext(ctx, query, args...)
		if err != nil {
			if strings.Contains(err.Error(), "UNIQUE constraint failed") {
				http.Error(w, "Gruppenname bereits vergeben", http.StatusConflict)
				return
			}
			http.Error(w, "Fehler beim Aktualisieren der Berechtigungsgruppe", http.StatusInternalServerError)
			log.Printf("Fehler beim Aktualisieren der Berechtigungsgruppe: %v", err)
			return
		}
	}

	// Aktualisiere Space-Zuweisungen, falls angegeben
	if req.SpaceIDs != nil {
		// Lösche alle bestehenden Space-Zuweisungen
		_, err = db.ExecContext(ctx, "DELETE FROM group_spaces WHERE group_id = ?", groupID)
		if err != nil {
			log.Printf("Fehler beim Löschen der Space-Zuweisungen: %v", err)
		}

		// Füge neue Space-Zuweisungen hinzu
		for _, spaceID := range req.SpaceIDs {
			// Prüfe ob Space existiert
			var exists bool
			err := db.QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM spaces WHERE id = ?)", spaceID).Scan(&exists)
			if err == nil && exists {
				_, err = db.ExecContext(ctx, "INSERT INTO group_spaces (group_id, space_id) VALUES (?, ?)", groupID, spaceID)
				if err != nil {
					log.Printf("Fehler beim Zuweisen des Space %s zur Gruppe: %v", spaceID, err)
				}
			}
		}
	}

	// Lade aktualisierte Gruppe
	var group PermissionGroup
	err = db.QueryRowContext(ctx, "SELECT id, name, description, permission, created_at FROM permission_groups WHERE id = ?", groupID).
		Scan(&group.ID, &group.Name, &group.Description, &group.Permission, &group.CreatedAt)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der aktualisierten Gruppe", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der aktualisierten Gruppe: %v", err)
		return
	}

	// Lade Space-IDs
	if req.SpaceIDs != nil {
		group.SpaceIDs = req.SpaceIDs
	} else {
		spaceRows, err := db.QueryContext(ctx, "SELECT space_id FROM group_spaces WHERE group_id = ?", groupID)
		if err == nil {
			var spaceIDs []string
			for spaceRows.Next() {
				var spaceID string
				if err := spaceRows.Scan(&spaceID); err == nil {
					spaceIDs = append(spaceIDs, spaceID)
				}
			}
			spaceRows.Close()
			group.SpaceIDs = spaceIDs
		}
	}

	json.NewEncoder(w).Encode(group)

	// Audit-Log
	requestUserID, requestUsername := getUserFromRequest(r)
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "UPDATE", "permission_group", groupID, requestUserID, requestUsername, map[string]interface{}{
		"name":       req.Name,
		"permission": req.Permission,
		"spaceIds":   req.SpaceIDs,
		"message":    fmt.Sprintf("Berechtigungsgruppe aktualisiert: %s", groupID),
	}, ipAddress, userAgent)
}

func deletePermissionGroupHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "DELETE, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	groupID := vars["id"]

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	result, err := db.ExecContext(ctx, "DELETE FROM permission_groups WHERE id = ?", groupID)
	if err != nil {
		http.Error(w, "Fehler beim Löschen der Berechtigungsgruppe", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen der Berechtigungsgruppe: %v", err)
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der gelöschten Zeilen", http.StatusInternalServerError)
		return
	}

	if rowsAffected == 0 {
		http.Error(w, "Berechtigungsgruppe nicht gefunden", http.StatusNotFound)
		return
	}

	response := MessageResponse{Message: "Berechtigungsgruppe erfolgreich gelöscht"}
	json.NewEncoder(w).Encode(response)

	// Audit-Log
	requestUserID, requestUsername := getUserFromRequest(r)
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "DELETE", "permission_group", groupID, requestUserID, requestUsername, map[string]interface{}{
		"message": fmt.Sprintf("Berechtigungsgruppe gelöscht: %s", groupID),
	}, ipAddress, userAgent)
}

// Passwortvalidierung nach Richtlinien
func validatePassword(password string) error {
	if len(password) < 8 {
		return fmt.Errorf("passwort muss mindestens 8 Zeichen lang sein")
	}

	hasUpper := false
	hasLower := false
	hasDigit := false
	hasSpecial := false

	for _, char := range password {
		switch {
		case 'A' <= char && char <= 'Z':
			hasUpper = true
		case 'a' <= char && char <= 'z':
			hasLower = true
		case '0' <= char && char <= '9':
			hasDigit = true
		default:
			// Prüfe auf Sonderzeichen (alles was nicht Buchstabe oder Zahl ist)
			if !(('A' <= char && char <= 'Z') || ('a' <= char && char <= 'z') || ('0' <= char && char <= '9')) {
				hasSpecial = true
			}
		}
	}

	var missing []string
	if !hasUpper {
		missing = append(missing, "Großbuchstaben")
	}
	if !hasLower {
		missing = append(missing, "Kleinbuchstaben")
	}
	if !hasDigit {
		missing = append(missing, "Zahlen")
	}
	if !hasSpecial {
		missing = append(missing, "Sonderzeichen")
	}

	if len(missing) > 0 {
		return fmt.Errorf("passwort muss enthalten: %s", strings.Join(missing, ", "))
	}

	return nil
}

// Helper-Funktion zum Extrahieren des Benutzers aus dem Request (für Basic Auth)
func getUserFromRequest(r *http.Request) (userID, username string) {
	auth := r.Header.Get("Authorization")
	if auth == "" || !strings.HasPrefix(auth, "Basic ") {
		return "", ""
	}

	encoded := strings.TrimPrefix(auth, "Basic ")
	decoded, err := base64.StdEncoding.DecodeString(encoded)
	if err != nil {
		return "", ""
	}

	parts := strings.SplitN(string(decoded), ":", 2)
	if len(parts) != 2 {
		return "", ""
	}

	username = parts[0]

	// Hole User-ID aus der Datenbank
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	var id string
	var enabled int
	err = db.QueryRowContext(ctx, "SELECT id, enabled FROM users WHERE username = ?", username).Scan(&id, &enabled)
	if err != nil {
		// Logge Fehler nur wenn es nicht "no rows" ist
		if err != sql.ErrNoRows {
			log.Printf("Fehler beim Abrufen der User-ID für %s: %v", username, err)
		}
		return "", username
	}

	// Prüfe ob User aktiviert ist
	if enabled == 0 {
		log.Printf("API-Zugriff für deaktivierten Benutzer: %s", username)
		return "", username
	}

	return id, username
}

// UserPermissionInfo enthält die Berechtigungsinformationen eines Benutzers
type UserPermissionInfo struct {
	UserID        string
	Groups        []PermissionGroupInfo
	HasFullAccess bool // true wenn der Benutzer mindestens eine FULL_ACCESS Gruppe hat
}

// PermissionGroupInfo enthält Informationen über eine Berechtigungsgruppe
type PermissionGroupInfo struct {
	GroupID    string
	Permission PermissionLevel
	SpaceIDs   []string // Leer bedeutet Zugriff auf alle Spaces
}

// isUserAdmin prüft, ob ein Benutzer Admin ist
func isUserAdmin(userID string) (bool, error) {
	if userID == "" {
		return false, nil
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	var isAdmin int
	err := db.QueryRowContext(ctx, "SELECT is_admin FROM users WHERE id = ?", userID).Scan(&isAdmin)
	if err != nil {
		if err == sql.ErrNoRows {
			return false, nil
		}
		return false, err
	}

	return isAdmin == 1, nil
}

// getUserPermissions ruft die Berechtigungen eines Benutzers ab
func getUserPermissions(userID string) (*UserPermissionInfo, error) {
	if userID == "" {
		return nil, fmt.Errorf("userID ist leer")
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	// Prüfe ob User Admin ist - Admins haben immer Vollzugriff
	isAdmin, err := isUserAdmin(userID)
	if err != nil {
		log.Printf("Fehler beim Prüfen des Admin-Status: %v", err)
	}
	if isAdmin {
		return &UserPermissionInfo{
			UserID:        userID,
			Groups:        []PermissionGroupInfo{},
			HasFullAccess: true,
		}, nil
	}

	// Hole alle Gruppen des Benutzers mit ihren Berechtigungen
	query := `
		SELECT pg.id, pg.permission
		FROM permission_groups pg
		INNER JOIN user_groups ug ON pg.id = ug.group_id
		WHERE ug.user_id = ?
	`
	rows, err := db.QueryContext(ctx, query, userID)
	if err != nil {
		return nil, fmt.Errorf("fehler beim Abrufen der Benutzergruppen: %w", err)
	}
	defer rows.Close()

	info := &UserPermissionInfo{
		UserID: userID,
		Groups: []PermissionGroupInfo{},
	}

	var groupIDs []string
	for rows.Next() {
		var groupID string
		var permission string
		if err := rows.Scan(&groupID, &permission); err != nil {
			continue
		}
		groupIDs = append(groupIDs, groupID)

		groupInfo := PermissionGroupInfo{
			GroupID:    groupID,
			Permission: PermissionLevel(permission),
			SpaceIDs:   []string{},
		}

		if PermissionLevel(permission) == PermissionFullAccess {
			info.HasFullAccess = true
		}

		info.Groups = append(info.Groups, groupInfo)
	}

	// Hole Space-Zuweisungen für alle Gruppen
	if len(groupIDs) > 0 {
		placeholders := make([]string, len(groupIDs))
		args := make([]interface{}, len(groupIDs))
		for i, id := range groupIDs {
			placeholders[i] = "?"
			args[i] = id
		}

		spaceQuery := fmt.Sprintf(`
			SELECT group_id, space_id
			FROM group_spaces
			WHERE group_id IN (%s)
		`, strings.Join(placeholders, ","))

		spaceRows, err := db.QueryContext(ctx, spaceQuery, args...)
		if err == nil {
			spaceMap := make(map[string][]string)
			for spaceRows.Next() {
				var groupID, spaceID string
				if err := spaceRows.Scan(&groupID, &spaceID); err == nil {
					spaceMap[groupID] = append(spaceMap[groupID], spaceID)
				}
			}
			spaceRows.Close()

			// Aktualisiere SpaceIDs für jede Gruppe
			for i := range info.Groups {
				if spaceIDs, exists := spaceMap[info.Groups[i].GroupID]; exists {
					info.Groups[i].SpaceIDs = spaceIDs
				}
			}
		}
	}

	return info, nil
}

// hasSpaceAccess prüft, ob ein Benutzer Zugriff auf einen bestimmten Space hat
func hasSpaceAccess(userID, spaceID string) (bool, error) {
	if userID == "" {
		return false, nil
	}

	// Admins haben immer Zugriff
	isAdmin, err := isUserAdmin(userID)
	if err == nil && isAdmin {
		return true, nil
	}

	permissions, err := getUserPermissions(userID)
	if err != nil {
		return false, err
	}

	// Wenn der Benutzer keine Gruppen hat und nicht Admin ist, hat er keinen Zugriff
	// Admins haben immer Zugriff (wird bereits oben geprüft)
	if !isAdmin && len(permissions.Groups) == 0 {
		return false, nil
	}

	// Prüfe für jede Gruppe, ob der Benutzer Zugriff auf den Space hat
	for _, group := range permissions.Groups {
		// Wenn die Gruppe keine Spaces zugewiesen hat, hat der Benutzer Zugriff auf alle Spaces
		if len(group.SpaceIDs) == 0 {
			return true, nil
		}
		// Prüfe, ob der Space in der Liste der zugewiesenen Spaces ist
		for _, assignedSpaceID := range group.SpaceIDs {
			if assignedSpaceID == spaceID {
				return true, nil
			}
		}
	}

	return false, nil
}

// hasPermission prüft, ob ein Benutzer eine bestimmte Berechtigung für einen Space hat
// requiredPermission kann READ, READ_WRITE oder FULL_ACCESS sein
func hasPermission(userID, spaceID string, requiredPermission PermissionLevel) (bool, error) {
	if userID == "" {
		return false, nil
	}

	// Admins haben immer alle Berechtigungen
	isAdmin, err := isUserAdmin(userID)
	if err == nil && isAdmin {
		return true, nil
	}

	permissions, err := getUserPermissions(userID)
	if err != nil {
		return false, err
	}

	// Wenn der Benutzer keine Gruppen hat und nicht Admin ist, hat er keine Berechtigung
	// Admins haben immer alle Berechtigungen (wird bereits oben geprüft)
	if !isAdmin && len(permissions.Groups) == 0 {
		return false, nil
	}

	// Prüfe für jede Gruppe
	for _, group := range permissions.Groups {
		hasAccess := false

		// Prüfe, ob der Benutzer Zugriff auf den Space hat
		if len(group.SpaceIDs) == 0 {
			// Keine Space-Zuweisungen = Zugriff auf alle Spaces
			hasAccess = true
		} else {
			// Prüfe, ob der Space in der Liste ist
			for _, assignedSpaceID := range group.SpaceIDs {
				if assignedSpaceID == spaceID {
					hasAccess = true
					break
				}
			}
		}

		if !hasAccess {
			continue
		}

		// Prüfe die Berechtigungsstufe
		switch requiredPermission {
		case PermissionRead:
			// READ, READ_WRITE und FULL_ACCESS haben alle READ-Berechtigung
			return true, nil
		case PermissionReadWrite:
			// READ_WRITE und FULL_ACCESS haben READ_WRITE-Berechtigung
			if group.Permission == PermissionReadWrite || group.Permission == PermissionFullAccess {
				return true, nil
			}
		case PermissionFullAccess:
			// Nur FULL_ACCESS hat FULL_ACCESS-Berechtigung
			if group.Permission == PermissionFullAccess {
				return true, nil
			}
		}
	}

	return false, nil
}

// getAccessibleSpaceIDs gibt alle Space-IDs zurück, auf die der Benutzer Zugriff hat
func getAccessibleSpaceIDs(userID string) ([]string, error) {
	if userID == "" {
		return []string{}, nil
	}

	// Prüfe ob User Admin ist - Admins haben Zugriff auf alle Spaces
	isAdmin, err := isUserAdmin(userID)
	if err == nil && isAdmin {
		// Hole alle Spaces für Admin
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
		defer cancel()

		rows, err := db.QueryContext(ctx, "SELECT id FROM spaces")
		if err != nil {
			return []string{}, err
		}
		defer rows.Close()

		var spaceIDs []string
		for rows.Next() {
			var spaceID string
			if err := rows.Scan(&spaceID); err == nil {
				spaceIDs = append(spaceIDs, spaceID)
			}
		}
		return spaceIDs, nil
	}

	permissions, err := getUserPermissions(userID)
	if err != nil {
		return []string{}, err
	}

	// Wenn der Benutzer keine Gruppen hat, hat er keinen Zugriff
	// (Admin wurde bereits oben behandelt)
	if len(permissions.Groups) == 0 {
		return []string{}, nil
	}

	// Sammle alle zugewiesenen Spaces
	spaceIDMap := make(map[string]bool)
	hasUnrestrictedAccess := false

	for _, group := range permissions.Groups {
		// Wenn eine Gruppe keine Spaces zugewiesen hat, hat der Benutzer Zugriff auf alle Spaces
		if len(group.SpaceIDs) == 0 {
			hasUnrestrictedAccess = true
			break
		}
		// Sammle alle zugewiesenen Spaces
		for _, spaceID := range group.SpaceIDs {
			spaceIDMap[spaceID] = true
		}
	}

	// Wenn der Benutzer Zugriff auf alle Spaces hat, hole alle Spaces aus der DB
	if hasUnrestrictedAccess {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
		defer cancel()

		rows, err := db.QueryContext(ctx, "SELECT id FROM spaces")
		if err != nil {
			return []string{}, err
		}
		defer rows.Close()

		var spaceIDs []string
		for rows.Next() {
			var spaceID string
			if err := rows.Scan(&spaceID); err == nil {
				spaceIDs = append(spaceIDs, spaceID)
			}
		}
		return spaceIDs, nil
	}

	// Konvertiere Map zu Slice
	spaceIDs := make([]string, 0, len(spaceIDMap))
	for spaceID := range spaceIDMap {
		spaceIDs = append(spaceIDs, spaceID)
	}

	return spaceIDs, nil
}

// Helper-Funktion zum Extrahieren von IP-Adresse und User-Agent aus Request
func getRequestInfo(r *http.Request) (ipAddress, userAgent string) {
	// Hole IP-Adresse
	ipAddress = r.RemoteAddr
	if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
		ipAddress = forwarded
	} else if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
		ipAddress = realIP
	}

	// Hole User-Agent
	userAgent = r.Header.Get("User-Agent")

	// Prüfe, ob es sich um einen API-Aufruf handelt
	// API-Aufrufe haben entweder keinen User-Agent oder einen speziellen Header
	if userAgent == "" || r.Header.Get("X-API-Request") == "true" || r.Header.Get("X-Request-Source") == "api" {
		userAgent = "API"
	}

	return ipAddress, userAgent
}

// Audit Log Handler
func getAuditLogsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Query-Parameter für Filterung und Pagination
	query := r.URL.Query()
	limitStr := query.Get("limit")
	offsetStr := query.Get("offset")
	actionFilter := query.Get("action")
	resourceTypeFilter := query.Get("resourceType")
	userIdFilter := query.Get("userId")

	// Standardwerte für Pagination
	limit := 100
	offset := 0

	if limitStr != "" {
		if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 1000 {
			limit = l
		}
	}

	if offsetStr != "" {
		if o, err := strconv.Atoi(offsetStr); err == nil && o >= 0 {
			offset = o
		}
	}

	// Baue SQL-Query mit Filtern
	whereClauses := []string{}
	args := []interface{}{}

	if actionFilter != "" {
		whereClauses = append(whereClauses, "action = ?")
		args = append(args, actionFilter)
	}

	if resourceTypeFilter != "" {
		whereClauses = append(whereClauses, "resource_type = ?")
		args = append(args, resourceTypeFilter)
	}

	if userIdFilter != "" {
		whereClauses = append(whereClauses, "user_id = ?")
		args = append(args, userIdFilter)
	}

	whereSQL := ""
	if len(whereClauses) > 0 {
		whereSQL = "WHERE " + strings.Join(whereClauses, " AND ")
	}

	// Zähle Gesamtanzahl für Pagination
	var totalCount int
	countSQL := "SELECT COUNT(*) FROM audit_logs " + whereSQL
	countCtx, countCancel := context.WithTimeout(context.Background(), time.Second*5)
	defer countCancel()
	err := db.QueryRowContext(countCtx, countSQL, args...).Scan(&totalCount)
	if err != nil {
		http.Error(w, "Fehler beim Zählen der Logs", http.StatusInternalServerError)
		log.Printf("Fehler beim Zählen der Logs: %v", err)
		return
	}

	// Hole Logs - Verwende Prepared Statement für bessere Kompatibilität
	var querySQL string
	var queryArgs []interface{}

	if whereSQL != "" {
		querySQL = fmt.Sprintf(`
			SELECT id, timestamp, user_id, username, action, resource_type, resource_id, details, ip_address, user_agent
			FROM audit_logs
			%s
			ORDER BY datetime(timestamp) DESC, id DESC
			LIMIT ? OFFSET ?
		`, whereSQL)
		queryArgs = make([]interface{}, len(args))
		copy(queryArgs, args)
		queryArgs = append(queryArgs, limit, offset)
	} else {
		querySQL = `
			SELECT id, timestamp, user_id, username, action, resource_type, resource_id, details, ip_address, user_agent
			FROM audit_logs
			ORDER BY datetime(timestamp) DESC, id DESC
			LIMIT ? OFFSET ?
		`
		queryArgs = []interface{}{limit, offset}
	}

	queryCtx, queryCancel := context.WithTimeout(context.Background(), time.Second*10)
	defer queryCancel() // Cancel wird erst aufgerufen, wenn die Funktion beendet ist

	rows, err := db.QueryContext(queryCtx, querySQL, queryArgs...)
	if err != nil {
		http.Error(w, "Fehler beim Abrufen der Logs", http.StatusInternalServerError)
		log.Printf("Fehler beim Abrufen der Logs: %v", err)
		return
	}
	defer rows.Close()

	log.Printf("SQL Query: %s, Args: %v (Count: %d)", querySQL, queryArgs, len(queryArgs))

	var logs []AuditLog
	rowCount := 0
	scanErrors := 0
	for rows.Next() {
		rowCount++
		var logEntry AuditLog
		var userID, username, resourceID, detailsJSON, ipAddress, userAgent sql.NullString

		err := rows.Scan(
			&logEntry.ID,
			&logEntry.Timestamp,
			&userID,
			&username,
			&logEntry.Action,
			&logEntry.ResourceType,
			&resourceID,
			&detailsJSON,
			&ipAddress,
			&userAgent,
		)
		if err != nil {
			scanErrors++
			log.Printf("Fehler beim Scannen der Log-Zeile %d: %v", rowCount, err)
			continue
		}

		if userID.Valid {
			logEntry.UserID = userID.String
		}
		if username.Valid {
			logEntry.Username = username.String
		}
		if resourceID.Valid {
			logEntry.ResourceID = resourceID.String
		}
		// Parse JSON details
		if detailsJSON.Valid && detailsJSON.String != "" {
			var detailsMap map[string]interface{}
			if err := json.Unmarshal([]byte(detailsJSON.String), &detailsMap); err == nil {
				// Convert map to JSON string for display
				if jsonBytes, err := json.Marshal(detailsMap); err == nil {
					logEntry.Details = string(jsonBytes)
				} else {
					logEntry.Details = detailsJSON.String
				}
			} else {
				// Fallback: use raw string if JSON parsing fails
				logEntry.Details = detailsJSON.String
			}
		}
		if ipAddress.Valid {
			logEntry.IPAddress = ipAddress.String
		}
		if userAgent.Valid {
			logEntry.UserAgent = userAgent.String
		}

		logs = append(logs, logEntry)
	}

	if err := rows.Err(); err != nil {
		log.Printf("Fehler beim Iterieren über die Zeilen: %v", err)
	}

	log.Printf("Zeilen gelesen: %d, Scan-Fehler: %d, Logs hinzugefügt: %d", rowCount, scanErrors, len(logs))

	response := map[string]interface{}{
		"logs":    logs,
		"total":   totalCount,
		"limit":   limit,
		"offset":  offset,
		"hasMore": offset+limit < totalCount,
	}

	log.Printf("Audit-Logs abgerufen: %d Einträge gefunden (Total: %d, Limit: %d, Offset: %d)", len(logs), totalCount, limit, offset)

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

// Handler zum Löschen aller Audit-Logs
func deleteAllAuditLogsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "DELETE, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Prüfe Bestätigung
	confirm := r.URL.Query().Get("confirm")
	if confirm != "true" {
		http.Error(w, "Bestätigung erforderlich. Verwende ?confirm=true", http.StatusBadRequest)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	// Lösche alle Audit-Logs
	result, err := db.ExecContext(ctx, "DELETE FROM audit_logs")
	if err != nil {
		http.Error(w, "Fehler beim Löschen der Audit-Logs", http.StatusInternalServerError)
		log.Printf("Fehler beim Löschen der Audit-Logs: %v", err)
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der gelöschten Zeilen", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der gelöschten Zeilen: %v", err)
		return
	}

	log.Printf("Alle Audit-Logs gelöscht: %d Einträge", rowsAffected)

	response := map[string]interface{}{
		"message":      "Alle Audit-Logs erfolgreich gelöscht",
		"deletedCount": rowsAffected,
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

// Handler zum Erstellen eines Test-Audit-Logs (für Testskripte)
func createTestAuditLogHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	var req struct {
		Action    string                 `json:"action"`
		Entity    string                 `json:"entity"`
		EntityID  string                 `json:"entityID"`
		UserID    string                 `json:"userID"`
		Username  string                 `json:"username"`
		Details   map[string]interface{} `json:"details"`
		IPAddress string                 `json:"ipAddress"`
		UserAgent string                 `json:"userAgent"`
	}

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Ungültige Anfrage", http.StatusBadRequest)
		return
	}

	if req.Action == "" || req.Entity == "" {
		http.Error(w, "action und entity sind erforderlich", http.StatusBadRequest)
		return
	}

	// Verwende AuditService zum Erstellen des Logs
	if auditService == nil {
		http.Error(w, "AuditService nicht initialisiert", http.StatusInternalServerError)
		return
	}

	// Erstelle Context für die Anfrage
	ctx := r.Context()

	// Track das Event
	auditService.Track(ctx, req.Action, req.Entity, req.EntityID, req.UserID, req.Username, req.Details, req.IPAddress, req.UserAgent)

	response := map[string]interface{}{
		"success": true,
		"message": "Test-Audit-Log erstellt",
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

// Basic Auth Middleware
func basicAuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// OPTIONS-Requests erlauben (für CORS)
		if r.Method == "OPTIONS" {
			next(w, r)
			return
		}

		// Prüfe ob es ein AJAX/Fetch-Request ist (kein Browser-Basic-Auth-Dialog)
		isAjaxRequest := r.Header.Get("X-Requested-With") == "XMLHttpRequest" ||
			strings.Contains(r.Header.Get("Content-Type"), "application/json") ||
			r.Header.Get("Accept") == "application/json" ||
			strings.HasPrefix(r.URL.Path, "/api/")

		// Prüfe Authorization Header
		auth := r.Header.Get("Authorization")
		if auth == "" {
			if !isAjaxRequest {
				w.Header().Set("WWW-Authenticate", `Basic realm="Certigo Addon"`)
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{"error": "Authentifizierung erforderlich"})
			return
		}

		// Parse Basic Auth
		if !strings.HasPrefix(auth, "Basic ") {
			if !isAjaxRequest {
				w.Header().Set("WWW-Authenticate", `Basic realm="Certigo Addon"`)
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Authentifizierung"})
			return
		}

		// Decode Base64
		encoded := strings.TrimPrefix(auth, "Basic ")
		decoded, err := base64.StdEncoding.DecodeString(encoded)
		if err != nil {
			if !isAjaxRequest {
				w.Header().Set("WWW-Authenticate", `Basic realm="Certigo Addon"`)
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Authentifizierung"})
			return
		}

		// Split username:password
		parts := strings.SplitN(string(decoded), ":", 2)
		if len(parts) != 2 {
			if !isAjaxRequest {
				w.Header().Set("WWW-Authenticate", `Basic realm="Certigo Addon"`)
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Authentifizierung"})
			return
		}

		username := parts[0]
		password := parts[1]

		// Validiere Benutzer
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
		defer cancel()

		var storedHash string
		var enabled int
		err = db.QueryRowContext(ctx, "SELECT password_hash, enabled FROM users WHERE username = ?", username).Scan(&storedHash, &enabled)
		if err != nil {
			if err == sql.ErrNoRows {
				if !isAjaxRequest {
					w.Header().Set("WWW-Authenticate", `Basic realm="Certigo Addon"`)
				}
				w.Header().Set("Content-Type", "application/json")
				w.WriteHeader(http.StatusUnauthorized)
				json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Anmeldedaten"})
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusInternalServerError)
			json.NewEncoder(w).Encode(map[string]string{"error": "Fehler bei der Authentifizierung"})
			log.Printf("Fehler bei der Authentifizierung: %v", err)
			return
		}

		// Prüfe ob User aktiviert ist
		if enabled == 0 {
			if !isAjaxRequest {
				w.Header().Set("WWW-Authenticate", `Basic realm="Certigo Addon"`)
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusForbidden)
			json.NewEncoder(w).Encode(map[string]string{"error": "Benutzerkonto ist deaktiviert"})
			return
		}

		// Prüfe Passwort
		err = bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(password))
		if err != nil {
			if !isAjaxRequest {
				w.Header().Set("WWW-Authenticate", `Basic realm="Certigo Addon"`)
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Anmeldedaten"})
			return
		}

		// Authentifizierung erfolgreich - weiterleiten
		next(w, r)
	}
}

// adminOnlyMiddleware prüft, ob der Benutzer ein Admin ist
func adminOnlyMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return basicAuthMiddleware(func(w http.ResponseWriter, r *http.Request) {
		userID, _ := getUserFromRequest(r)
		if userID == "" {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{"error": "Nicht authentifiziert"})
			return
		}

		isAdmin, err := isUserAdmin(userID)
		if err != nil {
			log.Printf("Fehler beim Prüfen des Admin-Status: %v", err)
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusInternalServerError)
			json.NewEncoder(w).Encode(map[string]string{"error": "Fehler beim Prüfen der Berechtigung"})
			return
		}

		if !isAdmin {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusForbidden)
			json.NewEncoder(w).Encode(map[string]string{"error": "Nur Administratoren haben Zugriff auf diese Funktion"})
			return
		}

		next(w, r)
	})
}

// Login Handler für Frontend (validiert Basic Auth und gibt User-Info zurück)
func loginHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	// Prüfe Authorization Header
	auth := r.Header.Get("Authorization")
	if auth == "" {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]string{"error": "Authentifizierung erforderlich"})
		return
	}

	// Parse Basic Auth
	if !strings.HasPrefix(auth, "Basic ") {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Authentifizierung"})
		return
	}

	// Decode Base64
	encoded := strings.TrimPrefix(auth, "Basic ")
	decoded, err := base64.StdEncoding.DecodeString(encoded)
	if err != nil {
		log.Printf("Fehler beim Decodieren der Basic Auth: %v", err)
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Authentifizierung"})
		return
	}

	// Split username:password
	parts := strings.SplitN(string(decoded), ":", 2)
	if len(parts) != 2 {
		log.Printf("Ungültiges Format in Basic Auth: %s", string(decoded))
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Authentifizierung"})
		return
	}

	username := parts[0]
	password := parts[1]

	log.Printf("Login-Versuch für Benutzer: %s", username)

	// Validiere Benutzer
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	var user User
	var storedHash string
	var enabled int
	err = db.QueryRowContext(ctx, "SELECT id, username, email, password_hash, enabled, created_at FROM users WHERE username = ?", username).
		Scan(&user.ID, &user.Username, &user.Email, &storedHash, &enabled, &user.CreatedAt)
	if err != nil {
		if err == sql.ErrNoRows {
			log.Printf("Benutzer nicht gefunden: %s", username)
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Anmeldedaten"})
			return
		}
		log.Printf("Fehler beim Abrufen des Benutzers: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		json.NewEncoder(w).Encode(map[string]string{"error": "Fehler bei der Authentifizierung"})
		return
	}

	// Prüfe ob User aktiviert ist
	if enabled == 0 {
		log.Printf("Login-Versuch für deaktivierten Benutzer: %s", username)
		w.WriteHeader(http.StatusForbidden)
		json.NewEncoder(w).Encode(map[string]string{"error": "Benutzerkonto ist deaktiviert"})
		return
	}

	// Prüfe Passwort
	err = bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(password))
	if err != nil {
		log.Printf("Passwort-Validierung fehlgeschlagen für Benutzer: %s", username)
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]string{"error": "Ungültige Anmeldedaten"})
		return
	}

	log.Printf("Login erfolgreich für Benutzer: %s", username)

	// Login erfolgreich
	response := map[string]interface{}{
		"success": true,
		"user":    user,
		"message": "Login erfolgreich",
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

func main() {
	log.Println("Starte certigo-addon Backend...")

	// Initialisiere Datenbank
	log.Println("Initialisiere Datenbank...")
	initDB()
	defer func() {
		log.Println("Schließe Datenbankverbindung...")
		db.Close()
	}()
	log.Println("Datenbank initialisiert")

	// Initialisiere Provider
	pm := providers.GetManager()
	pm.RegisterProvider(providers.NewDummyCAProvider())
	pm.RegisterProvider(providers.NewAutoDNSProvider())
	pm.RegisterProvider(providers.NewHetznerProvider())

	r := mux.NewRouter()

	// Swagger UI Route
	r.HandleFunc("/swagger", swaggerUIHandler).Methods("GET")
	r.HandleFunc("/api/openapi.yaml", openAPIHandler).Methods("GET")

	// API Routes
	api := r.PathPrefix("/api").Subrouter()

	// Public Routes (keine Auth erforderlich)
	api.HandleFunc("/health", healthHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/login", loginHandler).Methods("POST", "OPTIONS")

	// Protected Routes (Basic Auth erforderlich)
	api.HandleFunc("/stats", basicAuthMiddleware(getStatsHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces", basicAuthMiddleware(getSpacesHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces", basicAuthMiddleware(createSpaceHandler)).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{id}", basicAuthMiddleware(deleteSpaceHandler)).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns/count", basicAuthMiddleware(getSpaceFqdnCountHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns", basicAuthMiddleware(getFqdnsHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns", basicAuthMiddleware(createFqdnHandler)).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns", basicAuthMiddleware(deleteAllFqdnsHandler)).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns/{fqdnId}", basicAuthMiddleware(deleteFqdnHandler)).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/fqdns", basicAuthMiddleware(deleteAllFqdnsGlobalHandler)).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/csr", basicAuthMiddleware(uploadCSRHandler)).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/csr", basicAuthMiddleware(getCSRByFQDNHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/csrs", basicAuthMiddleware(deleteAllCSRsHandler)).Methods("DELETE", "OPTIONS")

	// User Routes (Admin only)
	api.HandleFunc("/users", adminOnlyMiddleware(getUsersHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/users", adminOnlyMiddleware(createUserHandler)).Methods("POST", "OPTIONS")
	api.HandleFunc("/users/{id}", adminOnlyMiddleware(getUserHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/users/{id}", adminOnlyMiddleware(updateUserHandler)).Methods("PUT", "OPTIONS")
	api.HandleFunc("/users/{id}", adminOnlyMiddleware(deleteUserHandler)).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/users/{id}/avatar", basicAuthMiddleware(getAvatarHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/users/{id}/avatar", basicAuthMiddleware(uploadAvatarHandler)).Methods("POST", "OPTIONS")
	api.HandleFunc("/user/permissions", basicAuthMiddleware(getUserPermissionsHandler)).Methods("GET", "OPTIONS")

	// Permission Groups Routes (Admin only)
	api.HandleFunc("/permission-groups", adminOnlyMiddleware(getPermissionGroupsHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/permission-groups", adminOnlyMiddleware(createPermissionGroupHandler)).Methods("POST", "OPTIONS")
	api.HandleFunc("/permission-groups/{id}", adminOnlyMiddleware(getPermissionGroupHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/permission-groups/{id}", adminOnlyMiddleware(updatePermissionGroupHandler)).Methods("PUT", "OPTIONS")
	api.HandleFunc("/permission-groups/{id}", adminOnlyMiddleware(deletePermissionGroupHandler)).Methods("DELETE", "OPTIONS")

	// Provider Routes (Protected)
	api.HandleFunc("/providers", basicAuthMiddleware(getProvidersHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/providers/{id}", basicAuthMiddleware(getProviderHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/providers/{id}/enabled", basicAuthMiddleware(setProviderEnabledHandler)).Methods("PUT", "OPTIONS")
	api.HandleFunc("/providers/{id}/config", basicAuthMiddleware(updateProviderConfigHandler)).Methods("PUT", "OPTIONS")
	api.HandleFunc("/providers/{id}/test", basicAuthMiddleware(testProviderConnectionHandler)).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/csr/sign", basicAuthMiddleware(signCSRHandler)).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/certificates", basicAuthMiddleware(getCertificatesHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/certificates/{certId}/refresh", basicAuthMiddleware(refreshCertificateHandler)).Methods("POST", "OPTIONS")

	// Audit Log Routes
	api.HandleFunc("/audit-logs", basicAuthMiddleware(getAuditLogsHandler)).Methods("GET", "OPTIONS")
	api.HandleFunc("/audit-logs", basicAuthMiddleware(deleteAllAuditLogsHandler)).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/audit-logs/test", basicAuthMiddleware(createTestAuditLogHandler)).Methods("POST", "OPTIONS")

	// Start server
	port := ":8080"
	log.Printf("Server läuft auf Port %s", port)
	log.Fatal(http.ListenAndServe(port, r))
}

// Provider Handlers

func getProvidersHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	pm := providers.GetManager()
	allProviders := pm.GetAllProviders()

	// Definiere feste Reihenfolge der Provider
	providerOrder := []string{"dummy-ca", "autodns", "hetzner"}

	// Erstelle Map für schnellen Zugriff
	providerMap := make(map[string]providers.ProviderInfo)
	for id, provider := range allProviders {
		config, _ := pm.GetProviderConfig(id)
		providerInfo := providers.ProviderInfo{
			ID:          id,
			Name:        provider.GetName(),
			DisplayName: provider.GetDisplayName(),
			Description: provider.GetDescription(),
			Enabled:     config.Enabled,
			Settings:    provider.GetRequiredSettings(),
		}
		providerMap[id] = providerInfo
	}

	// Sortiere nach definierter Reihenfolge
	var providerInfos []providers.ProviderInfo
	for _, id := range providerOrder {
		if providerInfo, exists := providerMap[id]; exists {
			providerInfos = append(providerInfos, providerInfo)
			delete(providerMap, id)
		}
	}

	// Füge alle anderen Provider hinzu, die nicht in der Liste sind
	for _, providerInfo := range providerMap {
		providerInfos = append(providerInfos, providerInfo)
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(providerInfos)
}

func getProviderHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	id := vars["id"]

	pm := providers.GetManager()
	provider, exists := pm.GetProvider(id)
	if !exists {
		http.Error(w, "Provider nicht gefunden", http.StatusNotFound)
		return
	}

	config, _ := pm.GetProviderConfig(id)
	providerInfo := providers.ProviderInfo{
		ID:          id,
		Name:        provider.GetName(),
		DisplayName: provider.GetDisplayName(),
		Description: provider.GetDescription(),
		Enabled:     config.Enabled,
		Settings:    provider.GetRequiredSettings(),
	}

	// Füge aktuelle Konfigurationswerte hinzu (ohne Passwörter)
	safeSettings := make(map[string]interface{})
	for key, value := range config.Settings {
		// Verstecke Passwörter und API Keys in der Antwort
		if key == "password" || key == "apiKey" {
			if str, ok := value.(string); ok && str != "" {
				safeSettings[key] = "***"
			} else {
				safeSettings[key] = value
			}
		} else {
			safeSettings[key] = value
		}
	}

	// Konvertiere zu JSON für die Response
	safeSettingsJSON, _ := json.Marshal(safeSettings)
	var safeSettingsMap map[string]interface{}
	json.Unmarshal(safeSettingsJSON, &safeSettingsMap)

	response := map[string]interface{}{
		"id":          providerInfo.ID,
		"name":        providerInfo.Name,
		"displayName": providerInfo.DisplayName,
		"description": providerInfo.Description,
		"enabled":     providerInfo.Enabled,
		"settings":    providerInfo.Settings,
		"config":      safeSettingsMap,
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

func setProviderEnabledHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "PUT, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	id := vars["id"]

	var req struct {
		Enabled bool `json:"enabled"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	pm := providers.GetManager()
	if err := pm.SetProviderEnabled(id, req.Enabled); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message": "Provider-Status erfolgreich aktualisiert",
		"enabled": req.Enabled,
	})

	// Audit-Log: Provider aktiviert/deaktiviert
	userID, username := getUserFromRequest(r)
	ipAddress, userAgent := getRequestInfo(r)
	action := "DISABLE"
	if req.Enabled {
		action = "ENABLE"
	}
	auditService.Track(r.Context(), action, "provider", id, userID, username, map[string]interface{}{
		"enabled": req.Enabled,
		"message": fmt.Sprintf("Provider %s %s", id, strings.ToLower(action)),
	}, ipAddress, userAgent)
}

func updateProviderConfigHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "PUT, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	id := vars["id"]

	var req struct {
		Settings map[string]interface{} `json:"settings"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	pm := providers.GetManager()
	config, _ := pm.GetProviderConfig(id)
	config.Settings = req.Settings

	if err := pm.UpdateProviderConfig(id, config); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message": "Konfiguration erfolgreich aktualisiert",
	})

	// Audit-Log: Provider-Konfiguration aktualisiert
	userID, username := getUserFromRequest(r)
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "UPDATE", "provider", id, userID, username, map[string]interface{}{
		"message": fmt.Sprintf("Provider-Konfiguration aktualisiert: %s", id),
	}, ipAddress, userAgent)
}

func testProviderConnectionHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	id := vars["id"]

	var req struct {
		Settings map[string]interface{} `json:"settings"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	pm := providers.GetManager()
	provider, exists := pm.GetProvider(id)
	if !exists {
		http.Error(w, "Provider nicht gefunden", http.StatusNotFound)
		return
	}

	if err := provider.TestConnection(req.Settings); err != nil {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"success": true,
		"message": "Verbindung erfolgreich",
	})
}

func signCSRHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["spaceId"]
	fqdnID := vars["fqdnId"]

	// Prüfe Berechtigung: READ_WRITE oder FULL_ACCESS erforderlich zum Signieren von CSRs
	userID, username := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasPermission, err := hasPermission(userID, spaceID, PermissionReadWrite)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasPermission {
		http.Error(w, "Keine Berechtigung zum Signieren von CSRs. Lesen/Schreiben oder Vollzugriff erforderlich.", http.StatusForbidden)
		return
	}

	var req struct {
		ProviderID string `json:"providerId"`
		CSRID      string `json:"csrId,omitempty"` // Optional: spezifischer CSR, sonst neuester
	}

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	if req.ProviderID == "" {
		http.Error(w, "providerId ist erforderlich", http.StatusBadRequest)
		return
	}

	// Hole neuesten CSR für den FQDN
	var csrPEM string
	var csrID string
	err = db.QueryRow(`
		SELECT id, csr_pem 
		FROM csrs 
		WHERE fqdn_id = ? AND space_id = ?
		ORDER BY created_at DESC 
		LIMIT 1
	`, fqdnID, spaceID).Scan(&csrID, &csrPEM)

	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Kein CSR für diesen FQDN gefunden", http.StatusNotFound)
			return
		}
		http.Error(w, "Fehler beim Laden des CSR", http.StatusInternalServerError)
		log.Printf("Fehler beim Laden des CSR: %v", err)
		return
	}

	// Wenn spezifischer CSR angefordert wurde
	if req.CSRID != "" && req.CSRID != csrID {
		err := db.QueryRow(`
			SELECT csr_pem 
			FROM csrs 
			WHERE id = ? AND fqdn_id = ? AND space_id = ?
		`, req.CSRID, fqdnID, spaceID).Scan(&csrPEM)

		if err != nil {
			if err == sql.ErrNoRows {
				http.Error(w, "CSR nicht gefunden", http.StatusNotFound)
				return
			}
			http.Error(w, "Fehler beim Laden des CSR", http.StatusInternalServerError)
			return
		}
		csrID = req.CSRID
	}

	// Hole Provider
	pm := providers.GetManager()
	provider, exists := pm.GetProvider(req.ProviderID)
	if !exists {
		http.Error(w, "Provider nicht gefunden", http.StatusNotFound)
		return
	}

	// Prüfe ob Provider aktiviert ist
	config, err := pm.GetProviderConfig(req.ProviderID)
	if err != nil || !config.Enabled {
		http.Error(w, "Provider ist nicht aktiviert", http.StatusBadRequest)
		return
	}

	// Signiere CSR
	result, err := provider.SignCSR(csrPEM, config.Settings)
	if err != nil {
		http.Error(w, fmt.Sprintf("Fehler beim Signieren des CSR: %v", err), http.StatusInternalServerError)
		log.Printf("Fehler beim Signieren des CSR: %v", err)
		return
	}

	// Speichere das Zertifikat in der DB
	certID := uuid.New().String()
	createdAt := time.Now()
	_, err = db.Exec(`
		INSERT INTO certificates (id, fqdn_id, space_id, csr_id, certificate_id, provider_id, certificate_pem, status, created_at)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
	`, certID, fqdnID, spaceID, csrID, result.OrderID, req.ProviderID, result.CertificatePEM, result.Status, createdAt)

	if err != nil {
		log.Printf("Fehler beim Speichern des Zertifikats: %v", err)
		// Weiterhin erfolgreich zurückgeben, auch wenn Speichern fehlschlägt
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"success":       true,
		"message":       result.Message,
		"certificateId": certID,
		"orderId":       result.OrderID,
		"status":        result.Status,
		"csrId":         csrID,
	})

	// Audit-Log: CSR signiert
	ipAddress, userAgent := getRequestInfo(r)
	auditService.Track(r.Context(), "SIGN", "csr", csrID, userID, username, map[string]interface{}{
		"providerId":    req.ProviderID,
		"fqdnId":        fqdnID,
		"spaceId":       spaceID,
		"certificateId": result.OrderID,
		"status":        result.Status,
		"message":       fmt.Sprintf("CSR signiert mit Provider %s für FQDN %s (Certificate ID: %s)", req.ProviderID, fqdnID, result.OrderID),
	}, ipAddress, userAgent)
}

func getCertificatesHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["spaceId"]
	fqdnID := vars["fqdnId"]

	// Prüfe Berechtigung: Benutzer muss Zugriff auf den Space haben (READ, READ_WRITE oder FULL_ACCESS)
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasAccess, err := hasSpaceAccess(userID, spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasAccess {
		http.Error(w, "Keine Berechtigung für diesen Space", http.StatusForbidden)
		return
	}

	// Hole alle Zertifikate für diesen FQDN
	rows, err := db.Query(`
		SELECT id, csr_id, certificate_id, provider_id, certificate_pem, status, created_at
		FROM certificates
		WHERE fqdn_id = ? AND space_id = ?
		ORDER BY created_at DESC
	`, fqdnID, spaceID)

	if err != nil {
		http.Error(w, "Fehler beim Laden der Zertifikate", http.StatusInternalServerError)
		log.Printf("Fehler beim Laden der Zertifikate: %v", err)
		return
	}
	defer rows.Close()

	var certificates []map[string]interface{}
	for rows.Next() {
		var id, csrID, certID, providerID, certPEM, status, createdAt string
		err := rows.Scan(&id, &csrID, &certID, &providerID, &certPEM, &status, &createdAt)
		if err != nil {
			log.Printf("Fehler beim Scannen der Zertifikat-Zeile: %v", err)
			continue
		}

		certificates = append(certificates, map[string]interface{}{
			"id":             id,
			"csrId":          csrID,
			"certificateId":  certID,
			"providerId":     providerID,
			"certificatePEM": certPEM,
			"status":         status,
			"createdAt":      createdAt,
		})
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(certificates)
}

func refreshCertificateHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	vars := mux.Vars(r)
	spaceID := vars["spaceId"]
	fqdnID := vars["fqdnId"]
	certID := vars["certId"]

	// Prüfe Berechtigung: Benutzer muss Zugriff auf den Space haben (READ, READ_WRITE oder FULL_ACCESS)
	userID, _ := getUserFromRequest(r)
	if userID == "" {
		http.Error(w, "Nicht authentifiziert", http.StatusUnauthorized)
		return
	}

	hasAccess, err := hasSpaceAccess(userID, spaceID)
	if err != nil {
		http.Error(w, "Fehler beim Prüfen der Berechtigung", http.StatusInternalServerError)
		log.Printf("Fehler beim Prüfen der Berechtigung: %v", err)
		return
	}

	if !hasAccess {
		http.Error(w, "Keine Berechtigung für diesen Space", http.StatusForbidden)
		return
	}

	// Hole Zertifikat aus DB
	var certificateID, providerID string
	err = db.QueryRow(`
		SELECT certificate_id, provider_id
		FROM certificates
		WHERE id = ? AND fqdn_id = ? AND space_id = ?
	`, certID, fqdnID, spaceID).Scan(&certificateID, &providerID)

	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Zertifikat nicht gefunden", http.StatusNotFound)
			return
		}
		http.Error(w, "Fehler beim Laden des Zertifikats", http.StatusInternalServerError)
		return
	}

	// Hole Provider
	pm := providers.GetManager()
	provider, exists := pm.GetProvider(providerID)
	if !exists {
		http.Error(w, "Provider nicht gefunden", http.StatusNotFound)
		return
	}

	// Prüfe ob Provider aktiviert ist
	config, err := pm.GetProviderConfig(providerID)
	if err != nil || !config.Enabled {
		http.Error(w, "Provider ist nicht aktiviert", http.StatusBadRequest)
		return
	}

	// Rufe Zertifikat von CA ab
	certPEM, err := provider.GetCertificate(certificateID, config.Settings)
	if err != nil {
		http.Error(w, fmt.Sprintf("Fehler beim Abrufen des Zertifikats: %v", err), http.StatusInternalServerError)
		return
	}

	// Aktualisiere Zertifikat in DB
	_, err = db.Exec(`
		UPDATE certificates
		SET certificate_pem = ?
		WHERE id = ? AND fqdn_id = ? AND space_id = ?
	`, certPEM, certID, fqdnID, spaceID)

	if err != nil {
		log.Printf("Fehler beim Aktualisieren des Zertifikats: %v", err)
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"success":        true,
		"certificatePEM": certPEM,
		"certificateId":  certificateID,
	})
}
