package httpapi

import (
	"net/http"
	"time"

	"github.com/easyai/easyai-ai-gateway/apps/api/internal/executionpool"
)

type AdminExecutionPoolWorker struct {
	WorkerID        string         `json:"workerId"`
	InstanceID      string         `json:"instanceId"`
	Revision        string         `json:"revision,omitempty"`
	ProtocolVersion string         `json:"protocolVersion"`
	Capabilities    map[string]any `json:"capabilities"`
	Allocated       int            `json:"allocated"`
	SafeCapacity    int            `json:"safeCapacity"`
	ActiveTasks     int            `json:"activeTasks"`
	PressureState   string         `json:"pressureState"`
	HeartbeatAt     time.Time      `json:"heartbeatAt"`
}

type AdminExecutionPool struct {
	PoolID       string                      `json:"poolId"`
	Labels       map[string]string           `json:"labels"`
	Capabilities map[string]any              `json:"capabilities"`
	State        string                      `json:"state"`
	Capacity     *AdminExecutionPoolCapacity `json:"capacity,omitempty"`
	Workers      []AdminExecutionPoolWorker  `json:"workers"`
}

type AdminExecutionPoolCapacity struct {
	WorkerCount             int       `json:"workerCount"`
	Allocated               int       `json:"allocated"`
	SafeCapacity            int       `json:"safeCapacity"`
	ActiveTasks             int       `json:"activeTasks"`
	HeavyCapacity           int       `json:"heavyCapacity"`
	HeavyTasks              int       `json:"heavyTasks"`
	QueueDepth              int       `json:"queueDepth"`
	EstimatedQueueWaitMilli int64     `json:"estimatedQueueWaitMs"`
	ResourceHeadroom        float64   `json:"resourceHeadroom"`
	Stability               float64   `json:"stability"`
	Critical                bool      `json:"critical"`
	SampledAt               time.Time `json:"sampledAt"`
}

type AdminRouteHealth struct {
	PoolID               string    `json:"poolId"`
	RouteProfileKey      string    `json:"routeProfileKey"`
	State                string    `json:"state"`
	SuccessRate          float64   `json:"successRate"`
	ConnectTLSP95Milli   int64     `json:"connectTlsP95Ms"`
	FirstByteP95Milli    int64     `json:"firstByteP95Ms"`
	UploadBytesPerSecond float64   `json:"uploadBytesPerSecond"`
	JitterP95Milli       int64     `json:"jitterP95Ms"`
	ConsecutiveFailures  int       `json:"consecutiveFailures"`
	ConsecutiveSuccesses int       `json:"consecutiveSuccesses"`
	SampleCount          int       `json:"sampleCount"`
	SampledAt            time.Time `json:"sampledAt"`
	ExpiresAt            time.Time `json:"expiresAt"`
}

type AdminExecutionPoolResponse struct {
	Pools       []AdminExecutionPool `json:"pools"`
	RouteHealth []AdminRouteHealth   `json:"routeHealth"`
	CapturedAt  time.Time            `json:"capturedAt"`
}

// listExecutionPools godoc
// @Summary 查询逻辑执行池、Worker 容量和上游路由健康状态
// @Tags Admin Runtime
// @Produce json
// @Success 200 {object} AdminExecutionPoolResponse
// @Failure 500 {object} ErrorEnvelope
// @Security BearerAuth
// @Router /api/admin/runtime/execution-pools [get]
func (s *Server) listExecutionPools(w http.ResponseWriter, r *http.Request) {
	now := time.Now()
	pools, err := s.coordinationStore.ListExecutionPools(r.Context())
	if err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}
	workers, err := s.coordinationStore.ListWorkers(r.Context(), now)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}
	capacities, err := s.coordinationStore.ListCapacity(r.Context(), now)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}
	health, err := s.coordinationStore.ListAllRouteHealth(r.Context())
	if err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}
	capacityByPool := make(map[string]executionpool.CapacitySnapshot, len(capacities))
	for _, capacity := range capacities {
		capacityByPool[capacity.PoolID] = capacity
	}
	workersByPool := make(map[string][]AdminExecutionPoolWorker)
	for _, worker := range workers {
		workersByPool[worker.PoolID] = append(workersByPool[worker.PoolID], AdminExecutionPoolWorker{
			WorkerID: worker.WorkerID, InstanceID: worker.InstanceID, Revision: worker.Revision,
			ProtocolVersion: worker.ProtocolVersion, Capabilities: worker.Capabilities,
			Allocated: worker.Allocated, SafeCapacity: worker.SafeCapacity,
			ActiveTasks: worker.ActiveTasks, PressureState: worker.PressureState,
			HeartbeatAt: worker.HeartbeatAt,
		})
	}
	response := AdminExecutionPoolResponse{
		Pools: make([]AdminExecutionPool, 0, len(pools)), RouteHealth: make([]AdminRouteHealth, 0, len(health)), CapturedAt: now,
	}
	for _, item := range health {
		response.RouteHealth = append(response.RouteHealth, AdminRouteHealth{
			PoolID: item.PoolID, RouteProfileKey: item.RouteProfileKey, State: string(item.State),
			SuccessRate: item.SuccessRate, ConnectTLSP95Milli: item.ConnectTLSP95.Milliseconds(),
			FirstByteP95Milli: item.FirstByteP95.Milliseconds(), UploadBytesPerSecond: item.UploadBytesPerSecond,
			JitterP95Milli: item.JitterP95.Milliseconds(), ConsecutiveFailures: item.ConsecutiveFailures,
			ConsecutiveSuccesses: item.ConsecutiveSuccesses, SampleCount: item.SampleCount,
			SampledAt: item.SampledAt, ExpiresAt: item.ExpiresAt,
		})
	}
	for _, pool := range pools {
		item := AdminExecutionPool{
			PoolID: pool.ID, Labels: pool.Labels, Capabilities: pool.Capabilities,
			State: string(pool.State), Workers: workersByPool[pool.ID],
		}
		if capacity, ok := capacityByPool[pool.ID]; ok {
			item.Capacity = &AdminExecutionPoolCapacity{
				WorkerCount: capacity.WorkerCount, Allocated: capacity.Allocated, SafeCapacity: capacity.SafeCapacity,
				ActiveTasks: capacity.ActiveTasks, HeavyCapacity: capacity.HeavyCapacity, HeavyTasks: capacity.HeavyTasks,
				QueueDepth: capacity.QueueDepth, EstimatedQueueWaitMilli: capacity.EstimatedQueueWait.Milliseconds(),
				ResourceHeadroom: capacity.ResourceHeadroom, Stability: capacity.Stability,
				Critical: capacity.Critical, SampledAt: capacity.SampledAt,
			}
		}
		response.Pools = append(response.Pools, item)
	}
	writeJSON(w, http.StatusOK, response)
}
