package httpapi_test

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"

	"github.com/wangjia/pangolin/server/api/gen"
	"github.com/wangjia/pangolin/server/internal/httpapi"
)

func newTestServer() http.Handler {
	r := chi.NewRouter()
	r.Use(middleware.Recoverer)
	gen.HandlerFromMuxWithBaseURL(&httpapi.UnimplementedServer{}, r, "/v1")
	return r
}

type errorBody struct {
	Code      string `json:"code"`
	MessageZH string `json:"message_zh"`
	MessageEn string `json:"message_en"`
}

func Test501StructuredBody(t *testing.T) {
	srv := newTestServer()

	// All defined /v1 routes should return 501 with the structured body.
	routes := []struct {
		method string
		path   string
	}{
		{"GET", "/v1/plans"},
		{"GET", "/v1/nodes"},
		{"GET", "/v1/me"},
		{"GET", "/v1/me/devices"},
		{"GET", "/v1/usage"},
		{"GET", "/v1/notices"},
		{"POST", "/v1/auth/code"},
		{"POST", "/v1/auth/register"},
		{"POST", "/v1/auth/login"},
		{"POST", "/v1/auth/refresh"},
		{"POST", "/v1/redeem"},
		{"POST", "/v1/ads/unlock"},
		{"DELETE", "/v1/me/devices/00000000-0000-0000-0000-000000000001"},
		{"POST", "/v1/nodes/00000000-0000-0000-0000-000000000001/connect"},
		{"POST", "/v1/nodes/00000000-0000-0000-0000-000000000001/disconnect"},
	}

	for _, tc := range routes {
		t.Run(tc.method+" "+tc.path, func(t *testing.T) {
			req := httptest.NewRequest(tc.method, tc.path, nil)
			rec := httptest.NewRecorder()
			srv.ServeHTTP(rec, req)

			if rec.Code != http.StatusNotImplemented {
				t.Errorf("expected 501, got %d", rec.Code)
			}

			var body errorBody
			if err := json.NewDecoder(rec.Body).Decode(&body); err != nil {
				t.Fatalf("could not decode body: %v", err)
			}
			if body.Code != "NOT_IMPLEMENTED" {
				t.Errorf("code: want NOT_IMPLEMENTED, got %q", body.Code)
			}
			if body.MessageZH == "" {
				t.Error("message_zh is empty")
			}
			if body.MessageEn == "" {
				t.Error("message_en is empty")
			}
		})
	}
}

func Test404ForUndefinedRoutes(t *testing.T) {
	srv := newTestServer()

	paths := []string{
		"/v1/nonexistent",
		"/v2/plans",
		"/totally/wrong",
	}

	for _, p := range paths {
		t.Run(p, func(t *testing.T) {
			req := httptest.NewRequest("GET", p, nil)
			rec := httptest.NewRecorder()
			srv.ServeHTTP(rec, req)

			if rec.Code != http.StatusNotFound {
				t.Errorf("path %s: expected 404, got %d", p, rec.Code)
			}
		})
	}
}

func TestHealthzNotAffected(t *testing.T) {
	r := chi.NewRouter()
	r.Get("/healthz", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(`{"status":"ok"}`))
	})
	gen.HandlerFromMuxWithBaseURL(&httpapi.UnimplementedServer{}, r, "/v1")

	req := httptest.NewRequest("GET", "/healthz", nil)
	rec := httptest.NewRecorder()
	r.ServeHTTP(rec, req)

	if rec.Code != http.StatusOK {
		t.Errorf("healthz: expected 200, got %d", rec.Code)
	}
}
