package handlers

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/go-chi/chi/v5"
	"golang.org/x/crypto/ssh"
	"xorm.io/xorm"

	"github.com/forgeo/forgebucket/internal/api/middleware"
	"github.com/forgeo/forgebucket/internal/models"
)

type SSHKeyHandler struct {
	db *xorm.Engine
}

func NewSSHKeyHandler(db *xorm.Engine) *SSHKeyHandler {
	return &SSHKeyHandler{db: db}
}

func (h *SSHKeyHandler) List(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.UserIDFromContext(r.Context())
	var keys []models.SSHKey
	if err := h.db.Where("user_id = ?", userID).Find(&keys); err != nil {
		jsonError(w, "could not list SSH keys", http.StatusInternalServerError)
		return
	}
	if keys == nil {
		keys = []models.SSHKey{}
	}
	jsonOK(w, keys)
}

func (h *SSHKeyHandler) Add(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.UserIDFromContext(r.Context())

	var body struct {
		Title     string `json:"title"`
		PublicKey string `json:"publicKey"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		jsonError(w, "invalid request body", http.StatusBadRequest)
		return
	}
	if body.Title == "" || body.PublicKey == "" {
		jsonError(w, "title and publicKey are required", http.StatusBadRequest)
		return
	}

	// Parse and validate the public key
	pubKeyBytes := []byte(strings.TrimSpace(body.PublicKey))
	pub, _, _, _, err := ssh.ParseAuthorizedKey(pubKeyBytes)
	if err != nil {
		jsonError(w, "invalid SSH public key format", http.StatusBadRequest)
		return
	}

	// Compute MD5 fingerprint (standard display format)
	fingerprint := fingerprintMD5(pub)

	key := &models.SSHKey{
		UserID:      userID,
		Title:       body.Title,
		Fingerprint: fingerprint,
		PublicKey:   strings.TrimSpace(body.PublicKey),
	}
	if _, err := h.db.Insert(key); err != nil {
		jsonError(w, "key already exists or could not be saved", http.StatusConflict)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(key)
}

func (h *SSHKeyHandler) Delete(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.UserIDFromContext(r.Context())
	keyID, err := strconv.ParseInt(chi.URLParam(r, "keyID"), 10, 64)
	if err != nil {
		jsonError(w, "invalid key ID", http.StatusBadRequest)
		return
	}

	n, err := h.db.Where("id = ? AND user_id = ?", keyID, userID).Delete(&models.SSHKey{})
	if err != nil || n == 0 {
		jsonError(w, "key not found", http.StatusNotFound)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

func fingerprintMD5(pub ssh.PublicKey) string {
	hash := md5.Sum(pub.Marshal())
	parts := make([]string, len(hash))
	for i, b := range hash {
		parts[i] = fmt.Sprintf("%02x", b)
	}
	return strings.Join(parts, ":")
}
