package updater

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

const sampleManifest = `{
  "schema_version": 1,
  "latest_stable": "v0.1.1",
  "releases": [
    {
      "version": "v0.1.0",
      "tarball_url": "https://releases.thaloco.com/banger/v0.1.0/banger-v0.1.0-linux-amd64.tar.gz",
      "sha256sums_url": "https://releases.thaloco.com/banger/v0.1.0/SHA256SUMS",
      "sha256sums_sig_url": "https://releases.thaloco.com/banger/v0.1.0/SHA256SUMS.sig",
      "released_at": "2026-04-29T10:00:00Z"
    },
    {
      "version": "v0.1.1",
      "tarball_url": "https://releases.thaloco.com/banger/v0.1.1/banger-v0.1.1-linux-amd64.tar.gz",
      "sha256sums_url": "https://releases.thaloco.com/banger/v0.1.1/SHA256SUMS",
      "sha256sums_sig_url": "https://releases.thaloco.com/banger/v0.1.1/SHA256SUMS.sig",
      "released_at": "2026-05-01T10:00:00Z"
    }
  ]
}`

func TestParseManifestHappyPath(t *testing.T) {
	m, err := ParseManifest([]byte(sampleManifest))
	if err != nil {
		t.Fatalf("ParseManifest: %v", err)
	}
	if m.LatestStable != "v0.1.1" || len(m.Releases) != 2 {
		t.Fatalf("manifest = %+v, want 2 releases with latest_stable=v0.1.1", m)
	}
}

func TestParseManifestRejectsNewerSchema(t *testing.T) {
	body := strings.Replace(sampleManifest, `"schema_version": 1`, `"schema_version": 99`, 1)
	_, err := ParseManifest([]byte(body))
	if err == nil || !strings.Contains(err.Error(), "newer than this CLI") {
		t.Fatalf("err = %v, want newer-schema rejection", err)
	}
}

func TestParseManifestRejectsMissingFields(t *testing.T) {
	for _, tc := range []struct {
		name string
		body string
	}{
		{name: "missing_schema_version", body: `{"latest_stable":"v0.1.0","releases":[]}`},
		{name: "missing_tarball_url", body: `{"schema_version":1,"latest_stable":"v0.1.0","releases":[{"version":"v0.1.0","sha256sums_url":"x"}]}`},
		{name: "missing_sha256sums_url", body: `{"schema_version":1,"latest_stable":"v0.1.0","releases":[{"version":"v0.1.0","tarball_url":"x"}]}`},
		{name: "empty_version", body: `{"schema_version":1,"latest_stable":"v0.1.0","releases":[{"tarball_url":"x","sha256sums_url":"y"}]}`},
		{name: "garbage", body: "not json"},
	} {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			if _, err := ParseManifest([]byte(tc.body)); err == nil {
				t.Fatalf("expected error parsing %s; got success", tc.name)
			}
		})
	}
}

func TestManifestLookupRelease(t *testing.T) {
	m, _ := ParseManifest([]byte(sampleManifest))
	r, err := m.LookupRelease("v0.1.0")
	if err != nil {
		t.Fatalf("LookupRelease(v0.1.0): %v", err)
	}
	if !strings.HasSuffix(r.TarballURL, "banger-v0.1.0-linux-amd64.tar.gz") {
		t.Fatalf("wrong tarball url: %s", r.TarballURL)
	}
	if _, err := m.LookupRelease("v9.9.9"); err == nil {
		t.Fatal("expected error looking up missing release")
	}
}

func TestManifestLatest(t *testing.T) {
	m, _ := ParseManifest([]byte(sampleManifest))
	r, err := m.Latest()
	if err != nil {
		t.Fatalf("Latest: %v", err)
	}
	if r.Version != "v0.1.1" {
		t.Fatalf("Latest.Version = %s, want v0.1.1", r.Version)
	}
}

func TestFetchManifestRoundTrip(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(sampleManifest))
	}))
	defer srv.Close()

	// Drive FetchManifest by overriding the global URL temporarily.
	prev := manifestURL
	manifestURL = srv.URL
	defer func() { manifestURL = prev }()

	m, err := FetchManifest(context.Background(), srv.Client())
	if err != nil {
		t.Fatalf("FetchManifest: %v", err)
	}
	if m.LatestStable != "v0.1.1" {
		t.Fatalf("LatestStable = %s", m.LatestStable)
	}
}
