package api

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

	"crypto-miner-server/internal/db"
	"crypto-miner-server/internal/models"
	"github.com/go-chi/chi/v5"
)

type Handler struct {
	db *db.Database
}

func NewHandler(database *db.Database) *Handler {
	return &Handler{db: database}
}

// GET /api/v1/dashboard/stats
func (h *Handler) GetDashboardStats(w http.ResponseWriter, r *http.Request) {
	stats, err := h.db.GetFleetStats()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJSON(w, stats)
}

// GET /api/v1/agents
func (h *Handler) ListAgents(w http.ResponseWriter, r *http.Request) {
	agents, err := h.db.ListAgents()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if agents == nil {
		agents = []*models.Agent{}
	}
	writeJSON(w, agents)
}

// GET /api/v1/agents/{id}
func (h *Handler) GetAgent(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	agent, err := h.db.GetAgent(id)
	if err != nil {
		http.Error(w, "Agent not found", http.StatusNotFound)
		return
	}
	writeJSON(w, agent)
}

// GET /api/v1/agents/{id}/stats
func (h *Handler) GetAgentStats(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	limitStr := r.URL.Query().Get("limit")
	limit := 100
	if l, err := strconv.Atoi(limitStr); err == nil && l > 0 {
		limit = l
	}
	if limit > 1000 {
		limit = 1000
	}
	samples, err := h.db.GetHashrateHistory(id, limit)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if samples == nil {
		samples = []*models.HashrateSample{}
	}
	writeJSON(w, samples)
}

// GET /api/v1/shares
func (h *Handler) GetRecentShares(w http.ResponseWriter, r *http.Request) {
	limitStr := r.URL.Query().Get("limit")
	limit := 50
	if l, err := strconv.Atoi(limitStr); err == nil && l > 0 {
		limit = l
	}
	if limit > 1000 {
		limit = 1000
	}
	shares, err := h.db.GetRecentShares(limit)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if shares == nil {
		shares = []*models.Share{}
	}
	writeJSON(w, shares)
}

// GET /api/v1/health
func (h *Handler) HealthCheck(w http.ResponseWriter, r *http.Request) {
	writeJSON(w, map[string]string{"status": "ok"})
}

// GET /api/v1/builds
func (h *Handler) ListBuilds(w http.ResponseWriter, r *http.Request) {
	builds, err := h.db.ListBuilds(50)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if builds == nil {
		builds = []*models.BuildRecord{}
	}
	writeJSON(w, builds)
}

// PUT /api/v1/builds/{id}/pin
// Pins the specified build as the active dropper target.
// Send an empty id or DELETE to a fake pin endpoint to unpin all.
func (h *Handler) PinBuild(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	if err := h.db.SetPinnedBuild(id); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJSON(w, map[string]interface{}{"ok": true, "pinned_id": id})
}

// DELETE /api/v1/builds/pin  (unpin all without deleting anything)
func (h *Handler) UnpinAll(w http.ResponseWriter, r *http.Request) {
	if err := h.db.SetPinnedBuild(""); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJSON(w, map[string]interface{}{"ok": true})
}

// DELETE /api/v1/builds/{id}
func (h *Handler) DeleteBuild(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	if err := h.db.DeleteBuild(id); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJSON(w, map[string]interface{}{"ok": true, "deleted_id": id})
}

func writeJSON(w http.ResponseWriter, v interface{}) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(v)
}
