package api

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/cynfo/rmm-backend/db"
)

// generateCustomerKey erstellt automatisch einen API-Key fuer einen Kunden
func generateCustomerKey(database *db.Database, customerID int, number, name, perm string) (*db.APIKey, error) {
	b := make([]byte, 16)
	if _, err := rand.Read(b); err != nil {
		return nil, err
	}
	key := hex.EncodeToString(b)
	var label string
	switch perm {
	case "agent":
		label = fmt.Sprintf("Agent — %s %s", number, name)
	case "read":
		label = fmt.Sprintf("Read-only — %s %s", number, name)
	default:
		label = fmt.Sprintf("%s — %s %s", perm, number, name)
	}
	return database.CreateAPIKey(label, key, perm, &customerID)
}

// GET /api/v1/customers
func (h *Handler) listCustomers(w http.ResponseWriter, r *http.Request) {
	customers, err := h.db.GetCustomers()
	if err != nil {
		writeError(w, http.StatusInternalServerError, "Fehler beim Laden")
		return
	}
	writeJSON(w, http.StatusOK, customers)
}

// POST /api/v1/customers
func (h *Handler) createCustomer(w http.ResponseWriter, r *http.Request) {
	var req struct {
		Number string `json:"number"`
		Name   string `json:"name"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Number == "" || req.Name == "" {
		writeError(w, http.StatusBadRequest, "number und name sind erforderlich")
		return
	}
	c, err := h.db.CreateCustomer(req.Number, req.Name)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "Kunde anlegen fehlgeschlagen")
		return
	}

	// Automatisch Agent-Key erstellen
	agentKey, err := generateCustomerKey(h.db, c.ID, req.Number, req.Name, "agent")
	if err != nil {
		log.Printf("Auto-Agent-Key fuer Kunde %s fehlgeschlagen: %v", req.Number, err)
	}

	h.auditLog(r, "customer.create", "customer", req.Number, req.Name, "")

	resp := map[string]interface{}{
		"customer":  c,
		"agent_key": agentKey,
	}
	writeJSON(w, http.StatusCreated, resp)
}

// GET /api/v1/customers/{id}
func (h *Handler) getCustomer(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.Atoi(r.PathValue("id"))
	if err != nil {
		writeError(w, http.StatusBadRequest, "Ungueltige ID")
		return
	}
	c, err := h.db.GetCustomer(id)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "Fehler beim Laden")
		return
	}
	if c == nil {
		writeError(w, http.StatusNotFound, "Kunde nicht gefunden")
		return
	}
	writeJSON(w, http.StatusOK, c)
}

// PUT /api/v1/customers/{id}
func (h *Handler) updateCustomer(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.Atoi(r.PathValue("id"))
	if err != nil {
		writeError(w, http.StatusBadRequest, "Ungueltige ID")
		return
	}
	var req struct {
		Number string `json:"number"`
		Name   string `json:"name"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Number == "" || req.Name == "" {
		writeError(w, http.StatusBadRequest, "number und name sind erforderlich")
		return
	}
	if err := h.db.UpdateCustomer(id, req.Number, req.Name); err != nil {
		writeError(w, http.StatusInternalServerError, "Aktualisierung fehlgeschlagen")
		return
	}
	writeJSON(w, http.StatusOK, map[string]string{"message": "Kunde aktualisiert"})
}

// DELETE /api/v1/customers/{id}
func (h *Handler) deleteCustomer(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.Atoi(r.PathValue("id"))
	if err != nil {
		writeError(w, http.StatusBadRequest, "Ungueltige ID")
		return
	}
	deleted, err := h.db.DeleteCustomer(id)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "Loeschen fehlgeschlagen")
		return
	}
	if !deleted {
		writeError(w, http.StatusNotFound, "Kunde nicht gefunden")
		return
	}
	h.auditLog(r, "customer.delete", "customer", strconv.Itoa(id), "", "")
	writeJSON(w, http.StatusOK, map[string]string{"message": "Kunde geloescht"})
}

// GET /api/v1/customers/{id}/agents
func (h *Handler) getCustomerAgents(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.Atoi(r.PathValue("id"))
	if err != nil {
		writeError(w, http.StatusBadRequest, "Ungueltige ID")
		return
	}
	agents, err := h.db.GetAgentsByCustomer(id)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "Fehler beim Laden")
		return
	}
	writeJSON(w, http.StatusOK, agents)
}

// PUT /api/v1/agents/{id}/customer
func (h *Handler) assignAgentCustomer(w http.ResponseWriter, r *http.Request) {
	agentID := r.PathValue("id")
	var req struct {
		CustomerID int `json:"customer_id"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.CustomerID == 0 {
		writeError(w, http.StatusBadRequest, "customer_id erforderlich")
		return
	}
	if err := h.db.AssignAgentCustomer(agentID, req.CustomerID); err != nil {
		writeError(w, http.StatusInternalServerError, "Zuordnung fehlgeschlagen")
		return
	}
	writeJSON(w, http.StatusOK, map[string]string{"message": "Agent zugeordnet"})
}

// DELETE /api/v1/agents/{id}/customer
func (h *Handler) unassignAgentCustomer(w http.ResponseWriter, r *http.Request) {
	agentID := r.PathValue("id")
	if err := h.db.UnassignAgentCustomer(agentID); err != nil {
		writeError(w, http.StatusInternalServerError, "Zuordnung entfernen fehlgeschlagen")
		return
	}
	writeJSON(w, http.StatusOK, map[string]string{"message": "Zuordnung entfernt"})
}
