package service

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"strings"
	"testing"
)

func TestHTTPHandlersCoverServiceRoutes(t *testing.T) {
	kube := fakeKubeServer(t)
	harbor := fakeHarborServer(t, true)
	installKubeFactory(t, kube)

	app := newTestApp(t)
	app.settings.Namespace = "maintenance"
	app.settings.RunnerImageARM64 = "runner:arm64"
	app.settings.HarborAPIBase = harbor.URL + "/api/v2.0"
	app.settings.HarborUsername = "admin"
	app.settings.HarborPassword = "pw"
	app.settings.HarborProject = "metis"
	app.settings.HarborRegistry = "registry.example"
	app.settings.ArtifactStatePath = filepath.Join(t.TempDir(), "artifacts.json")

	handler := app.Handler()

	t.Run("health", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
		resp := httptest.NewRecorder()
		handler.ServeHTTP(resp, req)
		if resp.Code != http.StatusOK || !strings.Contains(resp.Body.String(), `"status":"ok"`) {
			t.Fatalf("health response: %d %s", resp.Code, resp.Body.String())
		}
	})

	authHeaders := func(req *http.Request) {
		req.Header.Set("X-Auth-Request-User", "brad")
		req.Header.Set("X-Auth-Request-Groups", "admin")
	}

	t.Run("devices", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodGet, "/api/devices?host=titan-22", nil)
		authHeaders(req)
		resp := httptest.NewRecorder()
		handler.ServeHTTP(resp, req)
		if resp.Code != http.StatusOK || !strings.Contains(resp.Body.String(), `"/dev/sdz"`) {
			t.Fatalf("devices response: %d %s", resp.Code, resp.Body.String())
		}
	})

	t.Run("build", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodPost, "/api/jobs/build", strings.NewReader(`{"node":"titan-15"}`))
		req.Header.Set("Content-Type", "application/json")
		authHeaders(req)
		resp := httptest.NewRecorder()
		handler.ServeHTTP(resp, req)
		if resp.Code != http.StatusAccepted {
			t.Fatalf("build response: %d %s", resp.Code, resp.Body.String())
		}
		var job Job
		if err := json.Unmarshal(resp.Body.Bytes(), &job); err != nil {
			t.Fatalf("decode build job: %v", err)
		}
		waitForJobState(t, app, job.ID, JobDone)
	})

	t.Run("replace", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodPost, "/api/jobs/replace", strings.NewReader(`{"node":"titan-15","host":"titan-22","device":"/dev/sdz"}`))
		req.Header.Set("Content-Type", "application/json")
		authHeaders(req)
		resp := httptest.NewRecorder()
		handler.ServeHTTP(resp, req)
		if resp.Code != http.StatusAccepted {
			t.Fatalf("replace response: %d %s", resp.Code, resp.Body.String())
		}
		var job Job
		if err := json.Unmarshal(resp.Body.Bytes(), &job); err != nil {
			t.Fatalf("decode replace job: %v", err)
		}
		waitForJobState(t, app, job.ID, JobDone)
	})

	t.Run("watch", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodPost, "/api/sentinel/watch", nil)
		authHeaders(req)
		resp := httptest.NewRecorder()
		handler.ServeHTTP(resp, req)
		if resp.Code != http.StatusOK || !strings.Contains(resp.Body.String(), `"kind":"sentinel.watch"`) {
			t.Fatalf("watch response: %d %s", resp.Code, resp.Body.String())
		}
	})

	t.Run("index", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodGet, "/", nil)
		authHeaders(req)
		resp := httptest.NewRecorder()
		handler.ServeHTTP(resp, req)
		if resp.Code != http.StatusOK || !strings.Contains(resp.Body.String(), "<html") {
			t.Fatalf("index response: %d %s", resp.Code, resp.Body.String())
		}
	})
}
