package auth

import (
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
	"time"

	"github.com/example/sessionguard/internal/model"
	"golang.org/x/oauth2"
)

func TestManagerLoginUsesPKCES256(t *testing.T) {
	m := &Manager{
		cfg: model.OIDCConfig{SecureCookie: true},
		oauth: oauth2.Config{
			ClientID:    "client-1",
			RedirectURL: "https://director.example/oidc/callback",
			Endpoint:    oauth2.Endpoint{AuthURL: "https://login.example/authorize"},
		},
		pending: map[string]pending{},
		logout:  map[string]logoutSession{},
	}
	r := httptest.NewRequest("GET", "https://director.example/oidc/login", nil)
	w := httptest.NewRecorder()
	m.Login(w, r)

	loc, err := url.Parse(w.Header().Get("Location"))
	if err != nil {
		t.Fatal(err)
	}
	if got := loc.Query().Get("code_challenge_method"); got != "S256" {
		t.Fatalf("code_challenge_method=%q, want S256", got)
	}
	if got := loc.Query().Get("code_challenge"); got == "" {
		t.Fatal("missing code_challenge")
	}
	state := loc.Query().Get("state")
	m.mu.Lock()
	p, ok := m.pending[state]
	m.mu.Unlock()
	if !ok || p.CodeVerifier == "" {
		t.Fatal("PKCE verifier was not retained for callback exchange")
	}
}

func TestManagerLogoutUsesIDTokenHintAndRegisteredRedirect(t *testing.T) {
	const session = "signed-session-cookie"
	m := &Manager{
		cfg: model.OIDCConfig{
			ClientID:          "director-client",
			LogoutRedirectURL: "https://director.example/",
			SecureCookie:      true,
		},
		endSession: "https://login.example/api/oidc/end-session",
		pending:    map[string]pending{},
		logout: map[string]logoutSession{
			session: logoutSession{IDToken: "header.payload.signature", Exp: time.Now().Add(time.Hour)},
		},
	}
	r := httptest.NewRequest("GET", "https://director.example/logout", nil)
	r.AddCookie(&http.Cookie{Name: "sg_session", Value: session})
	w := httptest.NewRecorder()
	m.Logout(w, r)

	loc, err := url.Parse(w.Header().Get("Location"))
	if err != nil {
		t.Fatal(err)
	}
	q := loc.Query()
	if q.Get("client_id") != "director-client" {
		t.Fatalf("client_id=%q", q.Get("client_id"))
	}
	if q.Get("id_token_hint") != "header.payload.signature" {
		t.Fatalf("id_token_hint=%q", q.Get("id_token_hint"))
	}
	if q.Get("post_logout_redirect_uri") != "https://director.example/" {
		t.Fatalf("post_logout_redirect_uri=%q", q.Get("post_logout_redirect_uri"))
	}
	if !strings.Contains(w.Header().Get("Set-Cookie"), "sg_session=") {
		t.Fatal("local session cookie was not cleared")
	}
}
