package main

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

	"github.com/google/uuid"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"

	"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"`
}

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"`
}

var db *sql.DB

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*5)
		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)
	}

	log.Println("Datenbank erfolgreich initialisiert")
}

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 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
	}

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

	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
	}

	// Verwende Prepared Statement für bessere Performance und Sicherheit
	stmt, err := db.Prepare("SELECT id, name, description, created_at FROM spaces ORDER BY created_at DESC")
	if err != nil {
		http.Error(w, "Fehler beim Vorbereiten der Abfrage", http.StatusInternalServerError)
		log.Printf("Fehler beim Vorbereiten der Abfrage: %v", err)
		return
	}
	defer stmt.Close()

	rows, err := stmt.Query()
	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
	}

	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)
}

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 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"})
}

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
	}

	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 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 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)
}

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 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"})
}

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 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 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 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 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)
}

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 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
    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))
}

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()
	api.HandleFunc("/health", healthHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/stats", getStatsHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces", getSpacesHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces", createSpaceHandler).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{id}", deleteSpaceHandler).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns/count", getSpaceFqdnCountHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns", getFqdnsHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns", createFqdnHandler).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns", deleteAllFqdnsHandler).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/spaces/{id}/fqdns/{fqdnId}", deleteFqdnHandler).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/fqdns", deleteAllFqdnsGlobalHandler).Methods("DELETE", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/csr", uploadCSRHandler).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/csr", getCSRByFQDNHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/csrs", deleteAllCSRsHandler).Methods("DELETE", "OPTIONS")

	// Provider Routes
	api.HandleFunc("/providers", getProvidersHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/providers/{id}", getProviderHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/providers/{id}/enabled", setProviderEnabledHandler).Methods("PUT", "OPTIONS")
	api.HandleFunc("/providers/{id}/config", updateProviderConfigHandler).Methods("PUT", "OPTIONS")
	api.HandleFunc("/providers/{id}/test", testProviderConnectionHandler).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/csr/sign", signCSRHandler).Methods("POST", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/certificates", getCertificatesHandler).Methods("GET", "OPTIONS")
	api.HandleFunc("/spaces/{spaceId}/fqdns/{fqdnId}/certificates/{certId}/refresh", refreshCertificateHandler).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,
	})
}

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",
	})
}

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"]

	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,
	})
}

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"]

	// 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"]

	// 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,
	})
}
