package api

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

	"gitea.dooplex.hu/admin/felhom-hub/internal/store"
)

// doArtifacts GETs /artifacts/{id} with the passphrase header (the do() helper only sets Bearer).
func doArtifacts(h *Handler, customerID, pw string) *httptest.ResponseRecorder {
	req := httptest.NewRequest(http.MethodGet, "/api/v1/artifacts/"+customerID, nil)
	if pw != "" {
		req.Header.Set("X-Retrieval-Password", pw)
	}
	rr := httptest.NewRecorder()
	h.ServeHTTP(rr, req)
	return rr
}

// Scenario A — a recorded manifest is returned verbatim.
func TestArtifacts_ReturnsRecordedSet(t *testing.T) {
	h, st, _ := newTestHandler(t)
	st.SaveCustomerConfig(&store.CustomerConfig{CustomerID: "c1", APIKey: "ckey", RetrievalPassword: "pass-phrase"})
	if err := st.SetArtifactManifest(store.ArtifactManifest{
		AgentVersion:  "0.43.0",
		AgentSHA256:   strings.Repeat("a", 64),
		GoldenVersion: "0.85.1",
		GoldenSHA256:  strings.Repeat("b", 64),
	}); err != nil {
		t.Fatalf("SetArtifactManifest: %v", err)
	}

	rr := doArtifacts(h, "c1", "pass-phrase")
	if rr.Code != http.StatusOK {
		t.Fatalf("status = %d, body=%s", rr.Code, rr.Body.String())
	}
	var got artifactManifestResponse
	if err := json.Unmarshal(rr.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v", err)
	}
	if got.Agent.Version != "0.43.0" || got.Agent.SHA256 != strings.Repeat("a", 64) {
		t.Errorf("agent = %+v", got.Agent)
	}
	if got.Golden.Version != "0.85.1" || got.Golden.SHA256 != strings.Repeat("b", 64) {
		t.Errorf("golden = %+v", got.Golden)
	}
}

// Scenario B — an unset manifest returns 200 with empty fields (NOT an error). The script falls back
// to the local golden / fails clearly on a missing binary.
func TestArtifacts_EmptyWhenUnset(t *testing.T) {
	h, st, _ := newTestHandler(t)
	st.SaveCustomerConfig(&store.CustomerConfig{CustomerID: "c1", APIKey: "ckey", RetrievalPassword: "pass-phrase"})

	rr := doArtifacts(h, "c1", "pass-phrase")
	if rr.Code != http.StatusOK {
		t.Fatalf("status = %d, body=%s", rr.Code, rr.Body.String())
	}
	var got artifactManifestResponse
	if err := json.Unmarshal(rr.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v", err)
	}
	if got.Agent.Version != "" || got.Agent.SHA256 != "" || got.Golden.Version != "" || got.Golden.SHA256 != "" {
		t.Errorf("expected all-empty manifest, got %+v", got)
	}
}

// Scenario C — wrong passphrase is 401 (auth mirrors config-retrieve).
func TestArtifacts_WrongPassphrase(t *testing.T) {
	h, st, _ := newTestHandler(t)
	st.SaveCustomerConfig(&store.CustomerConfig{CustomerID: "c1", APIKey: "ckey", RetrievalPassword: "pass-phrase"})

	rr := doArtifacts(h, "c1", "wrong")
	if rr.Code != http.StatusUnauthorized {
		t.Fatalf("status = %d, want 401, body=%s", rr.Code, rr.Body.String())
	}
}

// Scenario D — missing passphrase header is 401.
func TestArtifacts_MissingPassphrase(t *testing.T) {
	h, st, _ := newTestHandler(t)
	st.SaveCustomerConfig(&store.CustomerConfig{CustomerID: "c1", APIKey: "ckey", RetrievalPassword: "pass-phrase"})

	rr := doArtifacts(h, "c1", "")
	if rr.Code != http.StatusUnauthorized {
		t.Fatalf("status = %d, want 401, body=%s", rr.Code, rr.Body.String())
	}
}

// Scenario E — unknown customer is 404 (before any auth comparison leaks).
func TestArtifacts_UnknownCustomer(t *testing.T) {
	h, _, _ := newTestHandler(t)

	rr := doArtifacts(h, "nope", "whatever")
	if rr.Code != http.StatusNotFound {
		t.Fatalf("status = %d, want 404, body=%s", rr.Code, rr.Body.String())
	}
}

// Scenario F — store round-trip: a partial set (agent only) persists independently.
func TestArtifacts_PartialSetRoundTrips(t *testing.T) {
	_, st, _ := newTestHandler(t)
	if err := st.SetArtifactManifest(store.ArtifactManifest{AgentVersion: "0.43.0", AgentSHA256: strings.Repeat("c", 64)}); err != nil {
		t.Fatalf("SetArtifactManifest: %v", err)
	}
	m := st.GetArtifactManifest()
	if m.AgentVersion != "0.43.0" || m.AgentSHA256 != strings.Repeat("c", 64) {
		t.Errorf("agent fields not round-tripped: %+v", m)
	}
	if m.GoldenVersion != "" || m.GoldenSHA256 != "" {
		t.Errorf("golden fields should be empty: %+v", m)
	}
}
