package server

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/openp2p-cn/inp2p/internal/store"
)

// helpers
func BearerToken(r *http.Request) string {
	h := r.Header.Get("Authorization")
	if h == "" {
		return ""
	}
	parts := strings.SplitN(h, " ", 2)
	if len(parts) != 2 {
		return ""
	}
	if strings.ToLower(parts[0]) != "bearer" {
		return ""
	}
	return strings.TrimSpace(parts[1])
}

func writeJSON(w http.ResponseWriter, status int, body string) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	io.WriteString(w, body)
}

func (s *Server) HandleAdminCreateTenant(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeJSON(w, http.StatusMethodNotAllowed, `{"error":1,"message":"method not allowed"}`)
		return
	}
	var req struct {
		Name string `json:"name"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Name == "" {
		writeJSON(w, http.StatusBadRequest, `{"error":1,"message":"bad request"}`)
		return
	}
	if s.store == nil {
		writeJSON(w, http.StatusInternalServerError, `{"error":1,"message":"store not ready"}`)
		return
	}
	ten, err := s.store.CreateTenant(req.Name)
	if err != nil {
		writeJSON(w, http.StatusInternalServerError, `{"error":1,"message":"create tenant failed"}`)
		return
	}
	resp := struct {
		Error   int    `json:"error"`
		Message string `json:"message"`
		Tenant  int64  `json:"tenant_id"`
		Subnet  string `json:"subnet"`
	}{0, "ok", ten.ID, ten.Subnet}
	b, _ := json.Marshal(resp)
	writeJSON(w, http.StatusOK, string(b))
}

func (s *Server) HandleAdminCreateAPIKey(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeJSON(w, http.StatusMethodNotAllowed, `{"error":1,"message":"method not allowed"}`)
		return
	}
	if s.store == nil {
		writeJSON(w, http.StatusInternalServerError, `{"error":1,"message":"store not ready"}`)
		return
	}
	// /api/v1/admin/tenants/{id}/keys
	parts := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
	if len(parts) < 6 || parts[5] != "keys" {
		writeJSON(w, http.StatusBadRequest, `{"error":1,"message":"bad request"}`)
		return
	}
	// parts: api v1 admin tenants {id} keys
	idPart := parts[4]
	var tenantID int64
	_, _ = fmt.Sscanf(idPart, "%d", &tenantID)
	if tenantID == 0 {
		writeJSON(w, http.StatusBadRequest, `{"error":1,"message":"bad request"}`)
		return
	}
	var req struct {
		Scope string `json:"scope"`
		TTL   int64  `json:"ttl"` // seconds
	}
	_ = json.NewDecoder(r.Body).Decode(&req)
	var ttl time.Duration
	if req.TTL > 0 {
		ttl = time.Duration(req.TTL) * time.Second
	}
	key, err := s.store.CreateAPIKey(tenantID, req.Scope, ttl)
	if err != nil {
		writeJSON(w, http.StatusInternalServerError, `{"error":1,"message":"create key failed"}`)
		return
	}
	resp := struct {
		Error   int    `json:"error"`
		Message string `json:"message"`
		APIKey  string `json:"api_key"`
		Tenant  int64  `json:"tenant_id"`
	}{0, "ok", key, tenantID}
	b, _ := json.Marshal(resp)
	writeJSON(w, http.StatusOK, string(b))
}

func (s *Server) HandleTenantEnroll(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeJSON(w, http.StatusMethodNotAllowed, `{"error":1,"message":"method not allowed"}`)
		return
	}
	// tenant auth by API key
	if s.store == nil {
		writeJSON(w, http.StatusInternalServerError, `{"error":1,"message":"store not ready"}`)
		return
	}
	tok := BearerToken(r)
	ten, err := s.store.VerifyAPIKey(tok)
	if err != nil || ten == nil {
		writeJSON(w, http.StatusUnauthorized, `{"error":1,"message":"unauthorized"}`)
		return
	}
	code, err := s.store.CreateEnrollToken(ten.ID, 10*time.Minute, 5)
	if err != nil {
		writeJSON(w, http.StatusInternalServerError, `{"error":1,"message":"create enroll failed"}`)
		return
	}
	resp := struct {
		Error   int    `json:"error"`
		Message string `json:"message"`
		Code    string `json:"enroll_code"`
		Tenant  int64  `json:"tenant_id"`
	}{0, "ok", code, ten.ID}
	b, _ := json.Marshal(resp)
	writeJSON(w, http.StatusOK, string(b))
}

func (s *Server) HandleEnrollConsume(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeJSON(w, http.StatusMethodNotAllowed, `{"error":1,"message":"method not allowed"}`)
		return
	}
	var req struct {
		Code     string `json:"code"`
		NodeName string `json:"node"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Code == "" || req.NodeName == "" {
		writeJSON(w, http.StatusBadRequest, `{"error":1,"message":"bad request"}`)
		return
	}
	if s.store == nil {
		writeJSON(w, http.StatusInternalServerError, `{"error":1,"message":"store not ready"}`)
		return
	}
	et, err := s.store.ConsumeEnrollToken(req.Code)
	if err != nil {
		s.store.IncEnrollAttempt(req.Code)
		writeJSON(w, http.StatusUnauthorized, `{"error":1,"message":"invalid enroll"}`)
		return
	}
	cred, err := s.store.CreateNodeCredential(et.TenantID, req.NodeName)
	if err != nil {
		writeJSON(w, http.StatusInternalServerError, `{"error":1,"message":"create node failed"}`)
		return
	}
	resp := struct {
		Error   int    `json:"error"`
		Message string `json:"message"`
		NodeID  int64  `json:"node_id"`
		Secret  string `json:"node_secret"`
		Tenant  int64  `json:"tenant_id"`
	}{0, "ok", cred.NodeID, cred.Secret, cred.TenantID}
	b, _ := json.Marshal(resp)
	writeJSON(w, http.StatusOK, string(b))
}

// placeholder to avoid unused import
var _ = store.Tenant{}
