package apispec_test

import (
	"io"
	"log/slog"
	"net/http"
	"strings"
	"testing"

	"github.com/go-chi/chi/v5"
	yaml "gopkg.in/yaml.v3"

	"github.com/aoagents/agent-orchestrator/backend/internal/config"
	"github.com/aoagents/agent-orchestrator/backend/internal/httpd"
	"github.com/aoagents/agent-orchestrator/backend/internal/httpd/apispec"
)

// TestRouteSpecParity asserts the mounted /api/v1 routes and the OpenAPI
// operations are in 1:1 correspondence — so a route can't be added without
// spec coverage, and the spec can't describe a route that isn't served.
func TestRouteSpecParity(t *testing.T) {
	log := slog.New(slog.NewTextHandler(io.Discard, nil))
	router := httpd.NewRouterWithControl(config.Config{}, log, nil, httpd.APIDeps{}, httpd.ControlDeps{})

	mounted := map[string]bool{}
	err := chi.Walk(router, func(method, route string, _ http.Handler, _ ...func(http.Handler) http.Handler) error {
		if strings.HasPrefix(route, "/api/v1/") && route != "/api/v1/openapi.yaml" {
			mounted[strings.ToUpper(method)+" "+route] = true
		}
		return nil
	})
	if err != nil {
		t.Fatalf("walk routes: %v", err)
	}
	if len(mounted) == 0 {
		t.Fatal("no /api/v1 routes mounted — router wiring changed?")
	}

	// Forward: every mounted route resolves to an operation slice.
	for r := range mounted {
		mp := strings.SplitN(r, " ", 2)
		if apispec.Default().Operation(mp[0], mp[1]) == nil {
			t.Errorf("mounted route %s has no OpenAPI operation", r)
		}
	}

	// Reverse: every spec operation is a mounted route.
	var doc struct {
		Paths map[string]map[string]yaml.Node `yaml:"paths"`
	}
	if err := yaml.Unmarshal(apispec.Default().YAML(), &doc); err != nil {
		t.Fatalf("parse spec: %v", err)
	}
	httpMethods := map[string]bool{"get": true, "post": true, "put": true, "patch": true, "delete": true}
	for path, item := range doc.Paths {
		for method := range item {
			if !httpMethods[method] {
				continue // skip parameters, summary, etc.
			}
			key := strings.ToUpper(method) + " " + path
			if !mounted[key] {
				t.Errorf("spec operation %s has no mounted route", key)
			}
		}
	}
}
