package auth

import (
	"errors"
	"fmt"
	"net/http"

	"github.com/netbirdio/netbird/proxy/auth"
	"github.com/netbirdio/netbird/proxy/internal/types"
	"github.com/netbirdio/netbird/shared/management/proto"
)

// ErrHeaderAuthFailed indicates that the header was present but the
// credential did not validate. Callers should return 401 instead of
// falling through to other auth schemes.
var ErrHeaderAuthFailed = errors.New("header authentication failed")

// Header implements header-based authentication. The proxy checks for the
// configured header in each request and validates its value via gRPC.
type Header struct {
	id         types.ServiceID
	accountId  types.AccountID
	headerName string
	client     authenticator
}

// NewHeader creates a Header authentication scheme for the given header name.
func NewHeader(client authenticator, id types.ServiceID, accountId types.AccountID, headerName string) Header {
	return Header{
		id:         id,
		accountId:  accountId,
		headerName: headerName,
		client:     client,
	}
}

// Type returns auth.MethodHeader.
func (Header) Type() auth.Method {
	return auth.MethodHeader
}

// Authenticate checks for the configured header in the request. If absent,
// returns empty (unauthenticated). If present, validates via gRPC.
func (h Header) Authenticate(r *http.Request) (string, string, error) {
	value := r.Header.Get(h.headerName)
	if value == "" {
		return "", "", nil
	}

	res, err := h.client.Authenticate(r.Context(), &proto.AuthenticateRequest{
		Id:        string(h.id),
		AccountId: string(h.accountId),
		Request: &proto.AuthenticateRequest_HeaderAuth{
			HeaderAuth: &proto.HeaderAuthRequest{
				HeaderValue: value,
				HeaderName:  h.headerName,
			},
		},
	})
	if err != nil {
		return "", "", fmt.Errorf("authenticate header: %w", err)
	}

	if res.GetSuccess() {
		return res.GetSessionToken(), "", nil
	}

	return "", "", ErrHeaderAuthFailed
}
