package middleware

import (
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/pingcap-inc/nexuscrm-api-host/hostruntime"
)

// SessionLookup is the result of projecting the host's authenticated request
// context into api-host's neutral session shape.
type SessionLookup struct {
	User   hostruntime.UserSession
	Exists bool
	Valid  bool
}

func (l SessionLookup) OK() bool {
	return l.Exists && l.Valid
}

// PermissionLookup preserves the distinction between "not installed yet" and
// "installed by the host in an invalid shape".
type PermissionLookup struct {
	Permissions map[string]bool
	Exists      bool
	Valid       bool
}

func (l PermissionLookup) OK() bool {
	return l.Exists && l.Valid
}

// SessionContextReader reads the current authenticated session without tying
// api-host middleware to a concrete backend auth.UserSession or context key.
type SessionContextReader interface {
	ReadSession(c *gin.Context) SessionLookup
}

// PermissionSessionContext owns the request-context facts that permission
// middleware reads or writes while staying independent from backend context keys.
type PermissionSessionContext interface {
	SessionContextReader
	WriteCurrentSession(c *gin.Context, user hostruntime.UserSession)
	WritePermissions(c *gin.Context, systemPerms, customPerms map[string]bool)
	SystemPermissions(c *gin.Context) PermissionLookup
	RequestID(c *gin.Context) string
}

// ScopeSessionContext owns the request-context facts that scoped OAuth routing
// contributes after a connected app request is accepted.
type ScopeSessionContext interface {
	SessionContextReader
	WriteConnectedAppID(c *gin.Context, connectedAppID string)
}

type noopPermissionSessionContext struct{}

func (noopPermissionSessionContext) ReadSession(*gin.Context) SessionLookup {
	return SessionLookup{}
}

func (noopPermissionSessionContext) WriteCurrentSession(*gin.Context, hostruntime.UserSession) {}

func (noopPermissionSessionContext) WritePermissions(*gin.Context, map[string]bool, map[string]bool) {
}

func (noopPermissionSessionContext) SystemPermissions(*gin.Context) PermissionLookup {
	return PermissionLookup{}
}

func (noopPermissionSessionContext) RequestID(*gin.Context) string {
	return ""
}

type noopScopeSessionContext struct {
	noopPermissionSessionContext
}

func (noopScopeSessionContext) WriteConnectedAppID(*gin.Context, string) {}

func NormalizePermissionSessionContext(ctx PermissionSessionContext) PermissionSessionContext {
	if ctx == nil {
		return noopPermissionSessionContext{}
	}
	return ctx
}

func NormalizeScopeSessionContext(ctx ScopeSessionContext) ScopeSessionContext {
	if ctx == nil {
		return noopScopeSessionContext{}
	}
	return ctx
}

func CanonicalConnectedAppID(connectedAppID string) string {
	return strings.TrimSpace(connectedAppID)
}
