package khatru

import (
	"context"

	"fiatjaf.com/nostr"
)

const (
	wsKey = iota
	subscriptionIdKey
	nip86HeaderAuthKey
	internalCallKey
)

func RequestAuth(ctx context.Context) {
	ws := GetConnection(ctx)
	ws.WriteJSON(nostr.AuthEnvelope{Challenge: &ws.Challenge})
}

func GetConnection(ctx context.Context) *WebSocket {
	wsi := ctx.Value(wsKey)
	if wsi != nil {
		return wsi.(*WebSocket)
	}
	return nil
}

// GetAuthed returns the last pubkey to have authenticated. Returns false if no one has.
//
// In a NIP-86 context it returns the single pubkey that have authenticated for that specific method call.
func GetAuthed(ctx context.Context) (nostr.PubKey, bool) {
	if conn := GetConnection(ctx); conn != nil {
		total := len(conn.AuthedPublicKeys)
		if total == 0 {
			return nostr.ZeroPK, false
		}
		return conn.AuthedPublicKeys[total-1], true
	}
	if nip86Auth := ctx.Value(nip86HeaderAuthKey); nip86Auth != nil {
		return nip86Auth.(nostr.PubKey), true
	}
	return nostr.ZeroPK, false
}

// IsAuthed checks if the given public key is among the multiple that may have potentially authenticated.
func IsAuthed(ctx context.Context, pubkey nostr.PubKey) bool {
	if conn := GetConnection(ctx); conn != nil {
		for _, pk := range conn.AuthedPublicKeys {
			if pk == pubkey {
				return true
			}
		}
	}

	if nip86Auth := ctx.Value(nip86HeaderAuthKey); nip86Auth != nil {
		return nip86Auth.(nostr.PubKey) == pubkey
	}

	return false
}

// IsInternalCall returns true when a call to QueryEvents, for example, is being made because of a deletion
// or expiration request.
func IsInternalCall(ctx context.Context) bool {
	return ctx.Value(internalCallKey) != nil
}

func GetIP(ctx context.Context) string {
	conn := GetConnection(ctx)
	if conn == nil {
		return ""
	}

	return GetIPFromRequest(conn.Request)
}

func GetSubscriptionID(ctx context.Context) string {
	return ctx.Value(subscriptionIdKey).(string)
}

func SendNotice(ctx context.Context, msg string) {
	GetConnection(ctx).WriteJSON(nostr.NoticeEnvelope(msg))
}
