package handlers

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

func TestSetStaticCacheHeaders(t *testing.T) {
	tests := map[string]string{
		"/static/css/00-base.css":   "public, max-age=86400",
		"/static/js/00-utils.js":    "public, max-age=86400",
		"/static/img/preview.webp":  "public, max-age=31536000, immutable",
		"/static/fonts/ui.woff2":    "public, max-age=31536000, immutable",
		"/static/videos/intro.mp4":  "public, max-age=31536000, immutable",
		"/static/uploads/file.data": "public, max-age=3600",
	}

	for path, want := range tests {
		response := httptest.NewRecorder()
		setStaticCacheHeaders(response, path)

		if got := response.Header().Get("Cache-Control"); got != want {
			t.Fatalf("Cache-Control for %s = %q, want %q", path, got, want)
		}
	}
}

func TestWebManifestIncludesShareTarget(t *testing.T) {
	data, err := os.ReadFile(filepath.Join("..", "..", "static", "site.webmanifest"))
	if err != nil {
		t.Fatalf("ReadFile returned error: %v", err)
	}
	var manifest struct {
		ShareTarget struct {
			Action  string `json:"action"`
			Method  string `json:"method"`
			EncType string `json:"enctype"`
			Params  struct {
				Title string `json:"title"`
				Text  string `json:"text"`
				URL   string `json:"url"`
				Files []struct {
					Name   string   `json:"name"`
					Accept []string `json:"accept"`
				} `json:"files"`
			} `json:"params"`
		} `json:"share_target"`
	}
	if err := json.Unmarshal(data, &manifest); err != nil {
		t.Fatalf("json.Unmarshal returned error: %v", err)
	}
	if manifest.ShareTarget.Action != "/share-target" || manifest.ShareTarget.Method != "POST" || manifest.ShareTarget.EncType != "multipart/form-data" {
		t.Fatalf("unexpected share_target config: %+v", manifest.ShareTarget)
	}
	if manifest.ShareTarget.Params.Title != "title" || manifest.ShareTarget.Params.Text != "text" || manifest.ShareTarget.Params.URL != "url" {
		t.Fatalf("unexpected share_target params: %+v", manifest.ShareTarget.Params)
	}
	if len(manifest.ShareTarget.Params.Files) != 1 || manifest.ShareTarget.Params.Files[0].Name != "files" || len(manifest.ShareTarget.Params.Files[0].Accept) != 1 || manifest.ShareTarget.Params.Files[0].Accept[0] != "*/*" {
		t.Fatalf("unexpected share_target files: %+v", manifest.ShareTarget.Params.Files)
	}
}

func TestServiceWorkerServedFromRootScope(t *testing.T) {
	app, cleanup := newTestApp(t)
	defer cleanup()

	request := httptest.NewRequest(http.MethodGet, "/service-worker.js", nil)
	response := httptest.NewRecorder()
	app.ServiceWorker(response, request)

	if response.Code != http.StatusOK {
		t.Fatalf("status = %d, body = %s", response.Code, response.Body.String())
	}
	if got := response.Header().Get("Service-Worker-Allowed"); got != "/" {
		t.Fatalf("Service-Worker-Allowed = %q, want /", got)
	}
	if got := response.Header().Get("Content-Type"); got != "text/javascript; charset=utf-8" {
		t.Fatalf("Content-Type = %q", got)
	}
	if response.Body.Len() == 0 {
		t.Fatalf("service worker body missing")
	}
}

func TestShareTargetFallbackRedirectsHome(t *testing.T) {
	app, cleanup := newTestApp(t)
	defer cleanup()

	request := httptest.NewRequest(http.MethodPost, "/share-target", nil)
	response := httptest.NewRecorder()
	app.ShareTargetFallback(response, request)

	if response.Code != http.StatusSeeOther {
		t.Fatalf("status = %d, want %d", response.Code, http.StatusSeeOther)
	}
	if got := response.Header().Get("Location"); got != "/?share-target=unsupported" {
		t.Fatalf("Location = %q", got)
	}
}
