package server

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

	"github.com/rs/zerolog/log"
)

// BootstrapPeer represents a libp2p bootstrap peer for CHORUS agent discovery
type BootstrapPeer struct {
	Multiaddr string `json:"multiaddr"` // libp2p multiaddr format: /ip4/{ip}/tcp/{port}/p2p/{peer_id}
	PeerID    string `json:"peer_id"`   // libp2p peer ID
	Name      string `json:"name"`      // Human-readable name
	Priority  int    `json:"priority"`  // Priority order (1 = highest)
}

// HandleBootstrapPeers returns list of bootstrap peers for CHORUS agent discovery
// GET /api/bootstrap-peers
//
// This endpoint provides a dynamic list of bootstrap peers that new CHORUS agents
// should connect to when joining the P2P mesh. The list includes:
// 1. HMMM monitor (priority 1) - For traffic observation
// 2. First 3 stable agents (priority 2-4) - For mesh formation
//
// Response format:
// {
//   "bootstrap_peers": [
//     {
//       "multiaddr": "/ip4/172.27.0.6/tcp/9001/p2p/12D3Koo...",
//       "peer_id": "12D3Koo...",
//       "name": "hmmm-monitor",
//       "priority": 1
//     }
//   ],
//   "updated_at": "2025-01-15T10:30:00Z"
// }
func (s *Server) HandleBootstrapPeers(w http.ResponseWriter, r *http.Request) {
	log.Info().Msg("📡 Bootstrap peers requested")

	var bootstrapPeers []BootstrapPeer

	// Get ALL connected agents from discovery - return complete dynamic list
	// This allows new agents AND the hmmm-monitor to discover the P2P mesh
	agents := s.p2pDiscovery.GetAgents()

	log.Debug().Int("total_agents", len(agents)).Msg("Discovered agents for bootstrap list")

	// HTTP client for fetching agent health endpoints
	client := &http.Client{Timeout: 5 * time.Second}

	for priority, agent := range agents {
		if agent.Endpoint == "" {
			log.Warn().Str("agent", agent.ID).Msg("Agent has no endpoint, skipping")
			continue
		}

		// Query agent health endpoint to get peer_id and multiaddrs
		healthURL := fmt.Sprintf("%s/api/health", strings.TrimRight(agent.Endpoint, "/"))
		log.Debug().Str("agent", agent.ID).Str("health_url", healthURL).Msg("Fetching agent health")

		resp, err := client.Get(healthURL)
		if err != nil {
			log.Warn().Str("agent", agent.ID).Err(err).Msg("Failed to fetch agent health")
			continue
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			log.Warn().Str("agent", agent.ID).Int("status", resp.StatusCode).Msg("Agent health check failed")
			continue
		}

		var health struct {
			PeerID     string   `json:"peer_id"`
			Multiaddrs []string `json:"multiaddrs"`
		}

		if err := json.NewDecoder(resp.Body).Decode(&health); err != nil {
			log.Warn().Str("agent", agent.ID).Err(err).Msg("Failed to decode health response")
			continue
		}

		// Add only the first multiaddr per agent to avoid duplicates
		// Each agent may have multiple interfaces but we only need one for bootstrap
		if len(health.Multiaddrs) > 0 {
			bootstrapPeers = append(bootstrapPeers, BootstrapPeer{
				Multiaddr: health.Multiaddrs[0],
				PeerID:    health.PeerID,
				Name:      agent.ID,
				Priority:  priority + 1,
			})

			log.Debug().
				Str("agent_id", agent.ID).
				Str("peer_id", health.PeerID).
				Str("multiaddr", health.Multiaddrs[0]).
				Int("priority", priority+1).
				Msg("Added agent to bootstrap list")
		}
	}

	response := map[string]interface{}{
		"bootstrap_peers": bootstrapPeers,
		"updated_at":      time.Now(),
		"count":           len(bootstrapPeers),
	}

	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(response); err != nil {
		log.Error().Err(err).Msg("Failed to encode bootstrap peers response")
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	log.Info().
		Int("peer_count", len(bootstrapPeers)).
		Msg("✅ Bootstrap peers list returned")
}
