package trackers

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/rs/zerolog"

	"github.com/operator/command-center/internal/scrape"
)

func newTestAdapter(t *testing.T, baseURL string) scrape.Adapter {
	t.Helper()
	h := scrape.New(nil, scrape.Options{}, zerolog.Nop())
	a, err := newMAM(Config{
		ID:      "mam-test",
		Name:    "MyAnonamouse (test)",
		Type:    "mam",
		BaseURL: baseURL,
	}, h)
	if err != nil {
		t.Fatalf("newMAM: %v", err)
	}
	return a
}

func TestMAMRegistered(t *testing.T) {
	types := RegisteredTypes()
	found := false
	for _, t := range types {
		if t == "mam" {
			found = true
		}
	}
	if !found {
		t.Errorf("mam adapter not registered; got %v", types)
	}
}

func TestMAMFetchRatioHappyPath(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/jsonLoad.php" {
			http.NotFound(w, r)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		_, _ = w.Write([]byte(`{
			"username": "tester",
			"uploaded": "123456789",
			"downloaded": "12345678",
			"uploadedReal": "100000000",
			"downloadedReal": "10000000",
			"ratio": "10.00",
			"seedbonus": 42,
			"unsat": 0,
			"unsat_limit": 5,
			"class_text": "Vip"
		}`))
	}))
	defer srv.Close()

	a := newTestAdapter(t, srv.URL)
	snap, err := a.FetchRatio(context.Background())
	if err != nil {
		t.Fatalf("FetchRatio: %v", err)
	}
	if snap.DisplayedUploadedBytes == nil || *snap.DisplayedUploadedBytes != 123456789 {
		t.Errorf("uploaded: %v", snap.DisplayedUploadedBytes)
	}
	if snap.RealUploadedBytes == nil || *snap.RealUploadedBytes != 100000000 {
		t.Errorf("real uploaded: %v", snap.RealUploadedBytes)
	}
	if snap.DisplayedRatio == nil || *snap.DisplayedRatio != 10.0 {
		t.Errorf("ratio: %v", snap.DisplayedRatio)
	}
	if snap.RealRatio == nil || *snap.RealRatio != 10.0 {
		t.Errorf("real ratio: %v", snap.RealRatio)
	}
	if snap.BonusPoints == nil || *snap.BonusPoints != 42 {
		t.Errorf("bonus: %v", snap.BonusPoints)
	}
	if snap.ClassOrRank != "Vip" {
		t.Errorf("class: %q", snap.ClassOrRank)
	}
	if snap.RawJSON == "" {
		t.Errorf("raw json not preserved")
	}
}

func TestMAMFetchRatioFallsBackToDisplayedWhenRealAbsent(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		_, _ = w.Write([]byte(`{
			"uploaded": "500",
			"downloaded": "100",
			"ratio": "5.00"
		}`))
	}))
	defer srv.Close()

	a := newTestAdapter(t, srv.URL)
	snap, err := a.FetchRatio(context.Background())
	if err != nil {
		t.Fatalf("FetchRatio: %v", err)
	}
	if snap.RealUploadedBytes == nil || *snap.RealUploadedBytes != 500 {
		t.Errorf("expected real to fall back to displayed=500, got %v", snap.RealUploadedBytes)
	}
}

func TestMAMFetchRatioErrorField(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(200)
		_, _ = w.Write([]byte(`{"error": "Invalid session"}`))
	}))
	defer srv.Close()

	a := newTestAdapter(t, srv.URL)
	_, err := a.FetchRatio(context.Background())
	if err == nil {
		t.Fatal("expected error on api error response")
	}
}

func TestMAMFetchRatio401(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(401)
	}))
	defer srv.Close()

	a := newTestAdapter(t, srv.URL)
	_, err := a.FetchRatio(context.Background())
	if err == nil {
		t.Fatal("expected error on 401")
	}
}

func TestMAMHealthOK(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(200)
	}))
	defer srv.Close()

	a := newTestAdapter(t, srv.URL)
	if err := a.Health(context.Background()); err != nil {
		t.Errorf("Health: %v", err)
	}
}

func TestMAMHealthAuthFailure(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(403)
	}))
	defer srv.Close()

	a := newTestAdapter(t, srv.URL)
	if err := a.Health(context.Background()); err == nil {
		t.Error("expected auth-failure error on 403")
	}
}

func TestNewWithUnknownTypeFails(t *testing.T) {
	_, err := New(Config{Type: "definitely-not-real", BaseURL: "https://x"}, scrape.New(nil, scrape.Options{}, zerolog.Nop()))
	if err == nil {
		t.Fatal("expected error on unknown adapter type")
	}
}
