package api

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"chorus.services/bzzz/logging"
	"chorus.services/bzzz/pubsub"
	"github.com/gorilla/mux"
)

// HTTPServer provides HTTP API endpoints for Bzzz
type HTTPServer struct {
	port         int
	hypercoreLog *logging.HypercoreLog
	pubsub       *pubsub.PubSub
	server       *http.Server
}

// NewHTTPServer creates a new HTTP server for Bzzz API
func NewHTTPServer(port int, hlog *logging.HypercoreLog, ps *pubsub.PubSub) *HTTPServer {
	return &HTTPServer{
		port:         port,
		hypercoreLog: hlog,
		pubsub:       ps,
	}
}

// Start starts the HTTP server
func (h *HTTPServer) Start() error {
	router := mux.NewRouter()
	
	// Enable CORS for all routes
	router.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Access-Control-Allow-Origin", "*")
			w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
			w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
			
			if r.Method == "OPTIONS" {
				w.WriteHeader(http.StatusOK)
				return
			}
			
			next.ServeHTTP(w, r)
		})
	})
	
	// API routes
	api := router.PathPrefix("/api").Subrouter()
	
	// Hypercore log endpoints
	api.HandleFunc("/hypercore/logs", h.handleGetLogs).Methods("GET")
	api.HandleFunc("/hypercore/logs/recent", h.handleGetRecentLogs).Methods("GET")
	api.HandleFunc("/hypercore/logs/stats", h.handleGetLogStats).Methods("GET")
	api.HandleFunc("/hypercore/logs/since/{index}", h.handleGetLogsSince).Methods("GET")
	
	// Health check
	api.HandleFunc("/health", h.handleHealth).Methods("GET")
	
	// Status endpoint
	api.HandleFunc("/status", h.handleStatus).Methods("GET")
	
	h.server = &http.Server{
		Addr:         fmt.Sprintf(":%d", h.port),
		Handler:      router,
		ReadTimeout:  15 * time.Second,
		WriteTimeout: 15 * time.Second,
		IdleTimeout:  60 * time.Second,
	}
	
	fmt.Printf("🌐 Starting HTTP API server on port %d\n", h.port)
	return h.server.ListenAndServe()
}

// Stop stops the HTTP server
func (h *HTTPServer) Stop() error {
	if h.server != nil {
		return h.server.Close()
	}
	return nil
}

// handleGetLogs returns hypercore log entries
func (h *HTTPServer) handleGetLogs(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	
	// Parse query parameters
	query := r.URL.Query()
	startStr := query.Get("start")
	endStr := query.Get("end")
	limitStr := query.Get("limit")
	
	var start, end uint64
	var err error
	
	if startStr != "" {
		start, err = strconv.ParseUint(startStr, 10, 64)
		if err != nil {
			http.Error(w, "Invalid start parameter", http.StatusBadRequest)
			return
		}
	}
	
	if endStr != "" {
		end, err = strconv.ParseUint(endStr, 10, 64)
		if err != nil {
			http.Error(w, "Invalid end parameter", http.StatusBadRequest)
			return
		}
	} else {
		end = h.hypercoreLog.Length()
	}
	
	var limit int = 100 // Default limit
	if limitStr != "" {
		limit, err = strconv.Atoi(limitStr)
		if err != nil || limit <= 0 || limit > 1000 {
			limit = 100
		}
	}
	
	// Get log entries
	var entries []logging.LogEntry
	if endStr != "" || startStr != "" {
		entries, err = h.hypercoreLog.GetRange(start, end)
	} else {
		entries, err = h.hypercoreLog.GetRecentEntries(limit)
	}
	
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to get log entries: %v", err), http.StatusInternalServerError)
		return
	}
	
	response := map[string]interface{}{
		"entries":   entries,
		"count":     len(entries),
		"timestamp": time.Now().Unix(),
		"total":     h.hypercoreLog.Length(),
	}
	
	json.NewEncoder(w).Encode(response)
}

// handleGetRecentLogs returns the most recent log entries
func (h *HTTPServer) handleGetRecentLogs(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	
	// Parse limit parameter
	query := r.URL.Query()
	limitStr := query.Get("limit")
	
	limit := 50 // Default
	if limitStr != "" {
		if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 1000 {
			limit = l
		}
	}
	
	entries, err := h.hypercoreLog.GetRecentEntries(limit)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to get recent entries: %v", err), http.StatusInternalServerError)
		return
	}
	
	response := map[string]interface{}{
		"entries":   entries,
		"count":     len(entries),
		"timestamp": time.Now().Unix(),
		"total":     h.hypercoreLog.Length(),
	}
	
	json.NewEncoder(w).Encode(response)
}

// handleGetLogsSince returns log entries since a given index
func (h *HTTPServer) handleGetLogsSince(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	
	vars := mux.Vars(r)
	indexStr := vars["index"]
	
	index, err := strconv.ParseUint(indexStr, 10, 64)
	if err != nil {
		http.Error(w, "Invalid index parameter", http.StatusBadRequest)
		return
	}
	
	entries, err := h.hypercoreLog.GetEntriesSince(index)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to get entries since index: %v", err), http.StatusInternalServerError)
		return
	}
	
	response := map[string]interface{}{
		"entries":    entries,
		"count":      len(entries),
		"since_index": index,
		"timestamp":  time.Now().Unix(),
		"total":      h.hypercoreLog.Length(),
	}
	
	json.NewEncoder(w).Encode(response)
}

// handleGetLogStats returns statistics about the hypercore log
func (h *HTTPServer) handleGetLogStats(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	
	stats := h.hypercoreLog.GetStats()
	json.NewEncoder(w).Encode(stats)
}

// handleHealth returns health status
func (h *HTTPServer) handleHealth(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	
	health := map[string]interface{}{
		"status":     "healthy",
		"timestamp":  time.Now().Unix(),
		"log_entries": h.hypercoreLog.Length(),
	}
	
	json.NewEncoder(w).Encode(health)
}

// handleStatus returns detailed status information
func (h *HTTPServer) handleStatus(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	
	status := map[string]interface{}{
		"status":       "running",
		"timestamp":    time.Now().Unix(),
		"hypercore":    h.hypercoreLog.GetStats(),
		"api_version":  "1.0.0",
	}
	
	json.NewEncoder(w).Encode(status)
}