package gitlab_test

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

	"github.com/webinstall/webi-installers/internal/releases/gitlab"
)

const page1 = `[
  {
    "tag_name": "v2.0.0",
    "name": "v2.0.0",
    "released_at": "2025-06-01T12:00:00Z",
    "assets": {
      "sources": [
        {"format": "tar.gz", "url": "https://example.com/archive/v2.0.0.tar.gz"},
        {"format": "zip", "url": "https://example.com/archive/v2.0.0.zip"}
      ],
      "links": [
        {
          "id": 1,
          "name": "tool-v2.0.0-linux-amd64.tar.gz",
          "url": "https://example.com/tool-v2.0.0-linux-amd64.tar.gz",
          "direct_asset_path": "/binaries/linux-amd64",
          "link_type": "package"
        }
      ]
    }
  }
]`

const page2 = `[
  {
    "tag_name": "v1.0.0",
    "name": "v1.0.0",
    "released_at": "2024-01-15T08:00:00Z",
    "assets": {
      "sources": [
        {"format": "tar.gz", "url": "https://example.com/archive/v1.0.0.tar.gz"}
      ],
      "links": []
    }
  }
]`

func TestFetchPagination(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Go's http server decodes %2F back to /, so check RawPath
		// for the encoded form or Path for the decoded form.
		wantRaw := "/api/v4/projects/group%2Ftool/releases"
		wantDecoded := "/api/v4/projects/group/tool/releases"
		if r.URL.RawPath != wantRaw && r.URL.Path != wantDecoded {
			t.Errorf("unexpected path: raw=%q decoded=%q", r.URL.RawPath, r.URL.Path)
			http.NotFound(w, r)
			return
		}

		page := r.URL.Query().Get("page")
		w.Header().Set("X-Total-Pages", "2")

		switch page {
		case "", "1":
			w.Write([]byte(page1))
		case "2":
			w.Write([]byte(page2))
		default:
			http.NotFound(w, r)
		}
	}))
	defer srv.Close()

	ctx := context.Background()
	var batches int
	var allReleases []gitlab.Release

	for releases, err := range gitlab.Fetch(ctx, srv.Client(), srv.URL, "group/tool", nil) {
		if err != nil {
			t.Fatalf("batch %d: %v", batches, err)
		}
		batches++
		allReleases = append(allReleases, releases...)
	}

	if batches != 2 {
		t.Errorf("got %d batches, want 2", batches)
	}
	if len(allReleases) != 2 {
		t.Fatalf("got %d releases, want 2", len(allReleases))
	}

	// Page 1: v2.0.0
	r1 := allReleases[0]
	if r1.TagName != "v2.0.0" {
		t.Errorf("release[0].TagName = %q, want %q", r1.TagName, "v2.0.0")
	}
	if len(r1.Assets.Sources) != 2 {
		t.Errorf("release[0] has %d sources, want 2", len(r1.Assets.Sources))
	}
	if len(r1.Assets.Links) != 1 {
		t.Errorf("release[0] has %d links, want 1", len(r1.Assets.Links))
	}
	if r1.Assets.Links[0].LinkType != "package" {
		t.Errorf("release[0] link type = %q, want %q", r1.Assets.Links[0].LinkType, "package")
	}

	// Page 2: v1.0.0
	r2 := allReleases[1]
	if r2.TagName != "v1.0.0" {
		t.Errorf("release[1].TagName = %q, want %q", r2.TagName, "v1.0.0")
	}
	if len(r2.Assets.Links) != 0 {
		t.Errorf("release[1] has %d links, want 0", len(r2.Assets.Links))
	}
}

func TestFetchAuth(t *testing.T) {
	var gotAuth string
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		gotAuth = r.Header.Get("PRIVATE-TOKEN")
		w.Write([]byte("[]"))
	}))
	defer srv.Close()

	ctx := context.Background()
	auth := &gitlab.Auth{Token: "glpat-test123"}
	for _, err := range gitlab.Fetch(ctx, srv.Client(), srv.URL, "group/tool", auth) {
		if err != nil {
			t.Fatal(err)
		}
	}

	if gotAuth != "glpat-test123" {
		t.Errorf("PRIVATE-TOKEN = %q, want %q", gotAuth, "glpat-test123")
	}
}

func TestFetchSinglePage(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// No X-Total-Pages header — defaults to 1 page.
		w.Write([]byte(page1))
	}))
	defer srv.Close()

	ctx := context.Background()
	var batches int
	for _, err := range gitlab.Fetch(ctx, srv.Client(), srv.URL, "group/tool", nil) {
		if err != nil {
			t.Fatal(err)
		}
		batches++
	}

	if batches != 1 {
		t.Errorf("got %d batches, want 1 (no X-Total-Pages means single page)", batches)
	}
}

func TestFetchEarlyBreak(t *testing.T) {
	var requests int
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		requests++
		w.Header().Set("X-Total-Pages", "10")
		w.Write(fmt.Appendf(nil, `[{"tag_name":"v%d.0.0","name":"","released_at":"2025-01-01T00:00:00Z","assets":{"sources":[],"links":[]}}]`, requests))
	}))
	defer srv.Close()

	ctx := context.Background()
	for _, err := range gitlab.Fetch(ctx, srv.Client(), srv.URL, "group/tool", nil) {
		if err != nil {
			t.Fatal(err)
		}
		break // stop after first page
	}

	if requests != 1 {
		t.Errorf("server received %d requests, want 1", requests)
	}
}
