package edge

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

	"github.com/gin-gonic/gin"

	"gitlab.com/dynaweb/ains-microservices/pkg/config"
	"gitlab.com/dynaweb/ains-microservices/pkg/i18n"
	"gitlab.com/dynaweb/ains-microservices/pkg/jwt"
	"gitlab.com/dynaweb/ains-microservices/web"
)

func newTestRouter(t *testing.T) *gin.Engine {
	t.Helper()
	cfg := &config.Config{}
	cfg.JWT.Secret = "test-secret"
	cfg.JWT.Issuer = "ains-test"
	cfg.JWT.AccessTTL = 60000000000
	cfg.JWT.RefreshTTL = 3600000000000
	cfg.I18n.DefaultLanguage = "ms"
	cfg.Auth.CookieName = "ains_token"
	cfg.Auth.Upstream = "http://127.0.0.1:8081"

	translator := i18n.New(cfg.I18n.DefaultLanguage)
	if err := web.LoadMessages(translator); err != nil {
		t.Fatal(err)
	}
	view, err := web.NewView(translator)
	if err != nil {
		t.Fatal(err)
	}
	handler, err := NewHandler(view, cfg, jwt.NewManager(cfg), translator)
	if err != nil {
		t.Fatal(err)
	}

	gin.SetMode(gin.TestMode)
	r := gin.New()
	if err := handler.Register(r); err != nil {
		t.Fatal(err)
	}
	return r
}

func get(r *gin.Engine, path string, cookie *http.Cookie) *httptest.ResponseRecorder {
	req := httptest.NewRequestWithContext(context.Background(), http.MethodGet, path, nil)
	if cookie != nil {
		req.AddCookie(cookie)
	}
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func TestHomeRenders(t *testing.T) {
	r := newTestRouter(t)
	w := get(r, "/", nil)
	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	if !strings.Contains(w.Body.String(), "AINS NILAM") {
		t.Fatal("home body missing brand")
	}
}

func TestStaticServed(t *testing.T) {
	r := newTestRouter(t)
	w := get(r, "/static/vendor/htmx.min.js", nil)
	if w.Code != http.StatusOK {
		t.Fatalf("static status = %d", w.Code)
	}
	if !strings.Contains(w.Header().Get("Content-Type"), "text/javascript") &&
		!strings.Contains(w.Header().Get("Content-Type"), "application/javascript") {
		t.Fatalf("content-type = %q", w.Header().Get("Content-Type"))
	}
}

func TestPing(t *testing.T) {
	r := newTestRouter(t)
	w := get(r, "/api/ping", nil)
	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	if !strings.Contains(w.Body.String(), "pong") {
		t.Fatalf("body = %q", w.Body.String())
	}
}

func TestLangSetsCookie(t *testing.T) {
	r := newTestRouter(t)
	req := httptest.NewRequestWithContext(context.Background(), http.MethodGet, "/lang?lang=en", nil)
	req.Header.Set("Referer", "/")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	if w.Code != http.StatusFound {
		t.Fatalf("status = %d", w.Code)
	}
	found := false
	for _, c := range w.Result().Cookies() {
		if c.Name == langCookieName && c.Value == "en" {
			found = true
		}
	}
	if !found {
		t.Fatal("ains_lang=en cookie not set")
	}
}

func TestUnknownPageNotFound(t *testing.T) {
	r := newTestRouter(t)
	w := get(r, "/web/nope", nil)
	if w.Code != http.StatusNotFound {
		t.Fatalf("status = %d", w.Code)
	}
}

func TestUserFromCookie(t *testing.T) {
	cfg := &config.Config{}
	cfg.JWT.Secret = "test-secret"
	cfg.JWT.Issuer = "ains-test"
	cfg.JWT.AccessTTL = 60000000000
	cfg.Auth.CookieName = "ains_token"
	cfg.Auth.Upstream = "http://127.0.0.1:8081"
	cfg.I18n.DefaultLanguage = "ms"

	translator := i18n.New(cfg.I18n.DefaultLanguage)
	_ = web.LoadMessages(translator)
	view, _ := web.NewView(translator)
	handler, _ := NewHandler(view, cfg, jwt.NewManager(cfg), translator)

	tokens := jwt.NewManager(cfg)
	access, err := tokens.IssueAccess(jwt.Identity{UserID: 7, Role: "teacher", School: "S1"})
	if err != nil {
		t.Fatal(err)
	}

	gin.SetMode(gin.TestMode)
	r := gin.New()
	if err := handler.Register(r); err != nil {
		t.Fatal(err)
	}

	w := get(r, "/", &http.Cookie{Name: "ains_token", Value: access})
	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	if !strings.Contains(w.Body.String(), "teacher") {
		t.Fatal("logged-in header should show role")
	}
}
