// Package queryparam provides a query param based implementation of a both
// as session store and loader.
package queryparam

import (
	"net/http"

	"github.com/pomerium/pomerium/internal/encoding"
	"github.com/pomerium/pomerium/internal/sessions"
)

var (
	_ sessions.SessionStore  = &Store{}
	_ sessions.SessionLoader = &Store{}
)

const (
	defaultQueryParamKey = "pomerium_session"
)

// Store implements the load session store interface using http
// query strings / query parameters.
type Store struct {
	queryParamKey string
	encoder       encoding.Marshaler
	decoder       encoding.Unmarshaler
}

// NewStore returns a new query param store for loading sessions from
// query strings / query parameters.
//
// NOTA BENE: By default, most servers _DO_ log query params, the leaking or
// accidental logging of which should be considered a security issue.
func NewStore(enc encoding.MarshalUnmarshaler, qp string) *Store {
	if qp == "" {
		qp = defaultQueryParamKey
	}
	return &Store{
		queryParamKey: qp,
		encoder:       enc,
		decoder:       enc,
	}
}

// LoadSession tries to retrieve the token string from URL query parameters.
func (qp *Store) LoadSession(r *http.Request) (string, error) {
	jwt := r.URL.Query().Get(qp.queryParamKey)
	if jwt == "" {
		return "", sessions.ErrNoSessionFound
	}

	return jwt, nil
}

// ClearSession clears the session cookie from a request's query param key `pomerium_session`.
func (qp *Store) ClearSession(_ http.ResponseWriter, r *http.Request) {
	params := r.URL.Query()
	params.Del(qp.queryParamKey)
	r.URL.RawQuery = params.Encode()
}

// SaveSession sets a session to a request's query param key `pomerium_session`
func (qp *Store) SaveSession(_ http.ResponseWriter, r *http.Request, x any) error {
	data, err := qp.encoder.Marshal(x)
	if err != nil {
		return err
	}
	r.URL.Query().Get(qp.queryParamKey)
	params := r.URL.Query()
	params.Set(qp.queryParamKey, string(data))
	r.URL.RawQuery = params.Encode()
	return nil
}