package collector

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

	"forge.lthn.ai/core/go/pkg/lab"
)

type Prometheus struct {
	url   string
	store *lab.Store
}

func NewPrometheus(promURL string, s *lab.Store) *Prometheus {
	return &Prometheus{url: promURL, store: s}
}

func (p *Prometheus) Name() string { return "prometheus" }

func (p *Prometheus) Collect(ctx context.Context) error {
	// Machine stats are handled by the system collector (direct /proc + SSH).
	// This collector only queries agent metrics from Prometheus.
	agents := lab.AgentSummary{}
	if v, err := p.query(ctx, "agents_registered_total"); err == nil && v != nil {
		agents.RegisteredTotal = int(*v)
		agents.Available = true
	}
	if v, err := p.query(ctx, "agents_queue_pending"); err == nil && v != nil {
		agents.QueuePending = int(*v)
	}
	if v, err := p.query(ctx, "agents_tasks_completed_total"); err == nil && v != nil {
		agents.TasksCompleted = int(*v)
	}
	if v, err := p.query(ctx, "agents_tasks_failed_total"); err == nil && v != nil {
		agents.TasksFailed = int(*v)
	}
	if v, err := p.query(ctx, "agents_capabilities_count"); err == nil && v != nil {
		agents.Capabilities = int(*v)
	}
	if v, err := p.query(ctx, "agents_heartbeat_age_seconds"); err == nil && v != nil {
		agents.HeartbeatAge = *v
	}
	if v, err := p.query(ctx, "agents_exporter_up"); err == nil && v != nil {
		agents.ExporterUp = *v > 0
	}

	p.store.SetAgents(agents)
	p.store.SetError("prometheus", nil)
	return nil
}

type promResponse struct {
	Status string `json:"status"`
	Data   struct {
		ResultType string `json:"resultType"`
		Result     []struct {
			Value [2]json.RawMessage `json:"value"`
		} `json:"result"`
	} `json:"data"`
}

func (p *Prometheus) query(ctx context.Context, promql string) (*float64, error) {
	u := fmt.Sprintf("%s/api/v1/query?query=%s", p.url, url.QueryEscape(promql))

	req, err := http.NewRequestWithContext(ctx, "GET", u, nil)
	if err != nil {
		return nil, err
	}

	client := &http.Client{Timeout: 5 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		p.store.SetError("prometheus", err)
		return nil, err
	}
	defer resp.Body.Close()

	var pr promResponse
	if err := json.NewDecoder(resp.Body).Decode(&pr); err != nil {
		return nil, err
	}

	if pr.Status != "success" || len(pr.Data.Result) == 0 {
		return nil, nil
	}

	var valStr string
	if err := json.Unmarshal(pr.Data.Result[0].Value[1], &valStr); err != nil {
		return nil, err
	}

	val, err := strconv.ParseFloat(valStr, 64)
	if err != nil {
		return nil, err
	}

	return &val, nil
}
