package updater

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

func TestNewUpdateService(t *testing.T) {
	svc := NewUpdateService("0.2.0")
	if svc.currentVersion != "0.2.0" {
		t.Errorf("currentVersion = %q, want %q", svc.currentVersion, "0.2.0")
	}
	if svc.baseURL == "" {
		t.Error("baseURL should not be empty")
	}
	if svc.owner == "" {
		t.Error("owner should not be empty")
	}
	if svc.pkg == "" {
		t.Error("pkg should not be empty")
	}
	if svc.httpClient == nil {
		t.Error("httpClient should not be nil")
	}
}

func TestNewUpdateServiceStripsVPrefix(t *testing.T) {
	svc := NewUpdateService("v1.2.3")
	if svc.currentVersion != "1.2.3" {
		t.Errorf("currentVersion = %q, want %q", svc.currentVersion, "1.2.3")
	}
}

func TestCompareVersions(t *testing.T) {
	tests := []struct {
		a, b string
		want int
	}{
		{"0.2.0", "0.2.1", -1},
		{"0.2.1", "0.2.0", 1},
		{"0.3.0", "0.2.9", 1},
		{"0.2.9", "0.3.0", -1},
		{"1.0.0", "0.9.9", 1},
		{"0.9.9", "1.0.0", -1},
		{"1.0.0", "1.0.0", 0},
		{"0.0.1", "0.0.1", 0},
		{"2.0.0", "1.99.99", 1},
		{"0.1.0", "0.0.99", 1},
		// With "v" prefix
		{"v0.2.0", "v0.2.1", -1},
		{"v1.0.0", "1.0.0", 0},
	}

	for _, tt := range tests {
		got := CompareVersions(tt.a, tt.b)
		if got != tt.want {
			t.Errorf("CompareVersions(%q, %q) = %d, want %d", tt.a, tt.b, got, tt.want)
		}
	}
}

func TestParseSemver(t *testing.T) {
	tests := []struct {
		input string
		want  [3]int
	}{
		{"1.2.3", [3]int{1, 2, 3}},
		{"0.0.0", [3]int{0, 0, 0}},
		{"10.20.30", [3]int{10, 20, 30}},
		{"1.2", [3]int{1, 2, 0}},
		{"1", [3]int{1, 0, 0}},
		{"", [3]int{0, 0, 0}},
	}

	for _, tt := range tests {
		got := parseSemver(tt.input)
		if got != tt.want {
			t.Errorf("parseSemver(%q) = %v, want %v", tt.input, got, tt.want)
		}
	}
}

func TestParseVersionJSON(t *testing.T) {
	raw := `{"version":"0.3.0","sha256":"abcdef1234567890","downloadUrl":"https://example.com/setup.exe"}`
	var v versionJSON
	if err := json.Unmarshal([]byte(raw), &v); err != nil {
		t.Fatalf("Unmarshal error: %v", err)
	}
	if v.Version != "0.3.0" {
		t.Errorf("Version = %q, want %q", v.Version, "0.3.0")
	}
	if v.SHA256 != "abcdef1234567890" {
		t.Errorf("SHA256 = %q, want %q", v.SHA256, "abcdef1234567890")
	}
	if v.DownloadURL != "https://example.com/setup.exe" {
		t.Errorf("DownloadURL = %q, want %q", v.DownloadURL, "https://example.com/setup.exe")
	}
}

func TestCheckForUpdate_NewerAvailable(t *testing.T) {
	// Mock the Gitea API: return a single package version that is newer.
	mux := http.NewServeMux()
	mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) {
		versions := []giteaPackageVersion{{Version: "0.3.0"}}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(versions)
	})
	mux.HandleFunc("/api/packages/vstockwell/generic/wraith/0.3.0/version.json", func(w http.ResponseWriter, r *http.Request) {
		v := versionJSON{
			Version:     "0.3.0",
			SHA256:      "abc123",
			DownloadURL: "https://example.com/wraith-0.3.0-setup.exe",
		}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(v)
	})
	server := httptest.NewServer(mux)
	defer server.Close()

	svc := NewUpdateService("0.2.0")
	svc.baseURL = server.URL

	info, err := svc.CheckForUpdate()
	if err != nil {
		t.Fatalf("CheckForUpdate() error: %v", err)
	}
	if !info.Available {
		t.Error("expected Available = true")
	}
	if info.LatestVer != "0.3.0" {
		t.Errorf("LatestVer = %q, want %q", info.LatestVer, "0.3.0")
	}
	if info.SHA256 != "abc123" {
		t.Errorf("SHA256 = %q, want %q", info.SHA256, "abc123")
	}
	if info.DownloadURL != "https://example.com/wraith-0.3.0-setup.exe" {
		t.Errorf("DownloadURL = %q, want %q", info.DownloadURL, "https://example.com/wraith-0.3.0-setup.exe")
	}
}

func TestCheckForUpdate_AlreadyUpToDate(t *testing.T) {
	mux := http.NewServeMux()
	mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) {
		versions := []giteaPackageVersion{{Version: "0.2.0"}}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(versions)
	})
	server := httptest.NewServer(mux)
	defer server.Close()

	svc := NewUpdateService("0.2.0")
	svc.baseURL = server.URL

	info, err := svc.CheckForUpdate()
	if err != nil {
		t.Fatalf("CheckForUpdate() error: %v", err)
	}
	if info.Available {
		t.Error("expected Available = false (same version)")
	}
}

func TestCheckForUpdate_CurrentIsNewer(t *testing.T) {
	mux := http.NewServeMux()
	mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) {
		versions := []giteaPackageVersion{{Version: "0.1.0"}}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(versions)
	})
	server := httptest.NewServer(mux)
	defer server.Close()

	svc := NewUpdateService("0.2.0")
	svc.baseURL = server.URL

	info, err := svc.CheckForUpdate()
	if err != nil {
		t.Fatalf("CheckForUpdate() error: %v", err)
	}
	if info.Available {
		t.Error("expected Available = false (current is newer)")
	}
}

func TestCheckForUpdate_NoVersions(t *testing.T) {
	mux := http.NewServeMux()
	mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode([]giteaPackageVersion{})
	})
	server := httptest.NewServer(mux)
	defer server.Close()

	svc := NewUpdateService("0.2.0")
	svc.baseURL = server.URL

	info, err := svc.CheckForUpdate()
	if err != nil {
		t.Fatalf("CheckForUpdate() error: %v", err)
	}
	if info.Available {
		t.Error("expected Available = false (no versions)")
	}
}

func TestCheckForUpdate_APIError(t *testing.T) {
	mux := http.NewServeMux()
	mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusInternalServerError)
	})
	server := httptest.NewServer(mux)
	defer server.Close()

	svc := NewUpdateService("0.2.0")
	svc.baseURL = server.URL

	_, err := svc.CheckForUpdate()
	if err == nil {
		t.Error("expected error from API failure")
	}
}
