package runtimeidentity

import (
	"context"
	"crypto/ed25519"
	"crypto/rand"
	"encoding/hex"
	"errors"
	"net/http"
	"time"

	"github.com/nexuscrm/backend/internal/runtimeapi"
	"github.com/pingcap-inc/nexuscrm-api-host/runtimegrpc"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/delegationv1"
	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/identityv1"
)

const (
	ProductionDelegationLifetime = 60 * time.Second
	ProductionVerifierClockSkew  = 5 * time.Second
	PlannedOldKeyOverlap         = ProductionDelegationLifetime + ProductionVerifierClockSkew
	CompromisedKeyOverlap        = 0
)

type PublicSession struct {
	SessionID string
	// State is projected by the same strong bearer admission that selected
	// SessionID. Keeping one value removes the former public-session then
	// bearer-free-session double read and prevents those projections from
	// becoming competing authority snapshots.
	State runtimeapi.RuntimeSessionState
}

type PublicSessionAuthority func(context.Context, string) (PublicSession, error)

// SessionCapabilityAuthority adapts the existing authoritative public-scope /
// Connected App policy to Runtime capability grants. It is required rather
// than defaulting an authenticated session to every requested capability. The
// returned set must use delegationv1's sorted, unique capability grammar;
// empty means the current session grants no Runtime capability.
type SessionCapabilityAuthority func(context.Context, runtimeapi.RuntimeSessionState) ([]string, error)

type IssuanceSecurityState struct {
	StateFound         bool
	BindingFound       bool
	BindingActive      bool
	OrgID              string
	RuntimeAudience    string
	Capabilities       []string
	SecurityEpoch      uint64
	LeaseFound         bool
	LeaseSecurityEpoch uint64
	LeaseExpiresAt     time.Time
}

type IssuanceSecuritySource func(context.Context, string, string) (IssuanceSecurityState, error)

type ActiveSigningKey struct {
	SigningKeyID string
	PrivateKey   ed25519.PrivateKey
}

type OverlapVerificationKey struct {
	SigningKeyID          string
	PublicKey             ed25519.PublicKey
	SigningStoppedAt      time.Time
	VerificationExpiresAt time.Time
	Compromised           bool
}

// SigningKeySnapshot is supplied by an operator-owned secret provider. Only
// the active key contains private material; overlap entries are verification
// keys with explicit P6-D windows.
type SigningKeySnapshot struct {
	Active  ActiveSigningKey
	Overlap []OverlapVerificationKey
}

type SigningKeyProvider func(context.Context, time.Time) (SigningKeySnapshot, error)
type DelegationIDGenerator func() (string, error)

type IssuerConfig struct {
	Bindings            runtimeapi.RuntimeBindingSource
	PublicSessions      PublicSessionAuthority
	SessionCapabilities SessionCapabilityAuthority
	Security            IssuanceSecuritySource
	SigningKeys         SigningKeyProvider
	DelegationIDs       DelegationIDGenerator
	Now                 func() time.Time
}

// Issuer is the single Runtime Identity production issuer. It contains no
// default Org, installation, capability, workload or signing-key fact.
type Issuer struct {
	bindings            runtimeapi.RuntimeBindingSource
	publicSessions      PublicSessionAuthority
	sessionCapabilities SessionCapabilityAuthority
	security            IssuanceSecuritySource
	signingKeys         SigningKeyProvider
	delegationIDs       DelegationIDGenerator
	now                 func() time.Time
}

func NewIssuer(config IssuerConfig) (*Issuer, error) {
	if config.Bindings == nil || config.PublicSessions == nil ||
		config.SessionCapabilities == nil || config.Security == nil || config.SigningKeys == nil {
		return nil, errors.New("runtime identity issuer: every authority port is required")
	}
	if config.DelegationIDs == nil {
		config.DelegationIDs = randomDelegationID
	}
	if config.Now == nil {
		config.Now = time.Now
	}
	return &Issuer{
		bindings: config.Bindings, publicSessions: config.PublicSessions,
		sessionCapabilities: config.SessionCapabilities, security: config.Security, signingKeys: config.SigningKeys,
		delegationIDs: config.DelegationIDs, now: config.Now,
	}, nil
}

func (i *Issuer) Exchange(ctx context.Context, request semantic.Request) (semantic.Response, error) {
	if i == nil {
		return semantic.Response{}, failure(semantic.FailureUnavailable)
	}
	if err := semantic.ValidateRequest(ctx, request); err != nil {
		return semantic.Response{}, err
	}
	caller, ok := runtimegrpc.Caller(ctx)
	if !ok {
		return semantic.Response{}, failure(semantic.FailureUnauthenticated)
	}
	bearer, ok := runtimegrpc.EndUserBearer(ctx)
	if !ok {
		return semantic.Response{}, failure(semantic.FailureUnauthenticated)
	}
	authorityCtx := runtimegrpc.WithoutEndUserBearer(ctx)

	binding, found, err := i.bindings(authorityCtx, caller)
	if err != nil {
		return semantic.Response{}, ownerFailure(ctx, err, semantic.FailureUnavailable)
	}
	if err := ctx.Err(); err != nil {
		return semantic.Response{}, err
	}
	if !found {
		return semantic.Response{}, failure(semantic.FailureForbidden)
	}
	if binding.CallerWorkloadID == "" {
		return semantic.Response{}, failure(semantic.FailureInternal)
	}

	publicSession, err := i.publicSessions(authorityCtx, bearer)
	if err != nil {
		return semantic.Response{}, sessionFailure(ctx, err)
	}
	if err := ctx.Err(); err != nil {
		return semantic.Response{}, err
	}
	durable := &publicSession.State
	if publicSession.SessionID == "" || durable.AuthEpoch == 0 || durable.User.ID == "" {
		return semantic.Response{}, failure(semantic.FailureInternal)
	}
	if err := durable.Subject.Validate(); err != nil {
		return semantic.Response{}, failure(semantic.FailureUnavailable)
	}
	if err := durable.PermissionFloor.Validate(); err != nil {
		return semantic.Response{}, failure(semantic.FailureUnavailable)
	}
	if durable.Subject.UserID() != durable.User.ID ||
		durable.Subject.ProfileID() != durable.User.ProfileID {
		return semantic.Response{}, failure(semantic.FailureUnavailable)
	}

	sessionCapabilities, err := i.sessionCapabilities(authorityCtx, *durable)
	if err != nil {
		return semantic.Response{}, ownerFailure(ctx, err, semantic.FailureUnavailable)
	}
	if err := ctx.Err(); err != nil {
		return semantic.Response{}, err
	}
	if len(sessionCapabilities) == 0 {
		return semantic.Response{}, failure(semantic.FailureForbidden)
	}

	state, err := i.security(authorityCtx, request.AppInstallationID, binding.CallerWorkloadID)
	if err != nil {
		return semantic.Response{}, ownerFailure(ctx, err, semantic.FailureUnavailable)
	}
	if err := ctx.Err(); err != nil {
		return semantic.Response{}, err
	}
	if !state.StateFound {
		return semantic.Response{}, failure(semantic.FailureUnavailable)
	}
	if !state.BindingFound || !state.BindingActive {
		return semantic.Response{}, failure(semantic.FailureForbidden)
	}
	authorityNow := i.now().UTC()
	if state.SecurityEpoch == 0 {
		return semantic.Response{}, failure(semantic.FailureInternal)
	}
	if !state.LeaseFound || state.LeaseSecurityEpoch != state.SecurityEpoch ||
		state.LeaseExpiresAt.IsZero() || !authorityNow.Before(state.LeaseExpiresAt) {
		return semantic.Response{}, &semantic.Failure{
			Category: semantic.FailureStaleState, StaleAxis: semantic.StaleAxisSecurity,
			RequiredRevision: state.SecurityEpoch, ServedRevision: state.LeaseSecurityEpoch,
		}
	}
	capabilities, err := delegationv1.IntersectCapabilities(delegationv1.CapabilityGrantSets{
		// The selected admission class supplies the closed caller/installation
		// grant: Catalog workload projection, or explicit user API caller plus
		// the matching prepared Catalog view. Session and request still narrow it.
		Workload: state.Capabilities, AppInstallation: state.Capabilities,
		Session: sessionCapabilities, Requested: request.RequestedCapabilities,
	})
	if err != nil {
		return semantic.Response{}, failure(semantic.FailureInternal)
	}
	if len(capabilities) == 0 {
		return semantic.Response{}, failure(semantic.FailureForbidden)
	}

	delegationID, err := i.delegationIDs()
	if err != nil || delegationID == "" {
		return semantic.Response{}, failure(semantic.FailureUnavailable)
	}
	if err := ctx.Err(); err != nil {
		return semantic.Response{}, err
	}
	issuedAt := authorityNow.Truncate(time.Second)
	expiresAt := issuedAt.Add(ProductionDelegationLifetime)
	claims := delegationv1.Claims{
		DelegationID: delegationID, OrgID: state.OrgID, PrincipalID: durable.User.ID,
		SessionID: publicSession.SessionID, CallerWorkloadID: binding.CallerWorkloadID,
		AppInstallationID: request.AppInstallationID, RuntimeAudience: state.RuntimeAudience,
		Capabilities: capabilities, AuthEpoch: durable.AuthEpoch, SecurityEpoch: state.SecurityEpoch,
		IssuedAt: issuedAt.Unix(), ExpiresAt: expiresAt.Unix(),
	}
	// A successful authority call that returns a value outside the already
	// approved P6 grammar is an internal invariant violation, not an authority
	// outage. Validate before consulting the operator key provider so corrupt
	// authority state can never reach signing.
	if err := claims.Validate(); err != nil {
		return semantic.Response{}, failure(semantic.FailureInternal)
	}
	keys, err := i.signingKeys(authorityCtx, authorityNow)
	if err != nil {
		return semantic.Response{}, ownerFailure(ctx, err, semantic.FailureUnavailable)
	}
	if err := ctx.Err(); err != nil {
		return semantic.Response{}, err
	}
	if _, err := keys.Verifier(authorityNow, capabilities); err != nil {
		return semantic.Response{}, failure(semantic.FailureUnavailable)
	}
	token, err := delegationv1.Sign(keys.Active.SigningKeyID, keys.Active.PrivateKey, claims)
	if err != nil {
		return semantic.Response{}, failure(semantic.FailureInternal)
	}
	response := semantic.Response{OpaqueDelegation: token, ExpiresAtUnixSecond: expiresAt.Unix()}
	if err := semantic.ValidateResponse(response); err != nil {
		return semantic.Response{}, failure(semantic.FailureInternal)
	}
	return response, nil
}

// Verifier creates the immutable admission key view for the same operator
// snapshot used by issuance. Planned overlap is exactly lifetime+skew;
// compromised keys are retired immediately and never accepted as overlap.
func (s SigningKeySnapshot) Verifier(now time.Time, supportedCapabilities []string) (*delegationv1.Verifier, error) {
	keys, err := s.verificationKeys(now)
	if err != nil {
		return nil, err
	}
	return delegationv1.NewVerifier(delegationv1.VerifierConfig{Keys: keys, SupportedCapabilities: supportedCapabilities, ClockSkew: ProductionVerifierClockSkew})
}

func (s SigningKeySnapshot) verificationKeys(now time.Time) ([]delegationv1.VerificationKey, error) {
	if len(s.Active.PrivateKey) != ed25519.PrivateKeySize || s.Active.SigningKeyID == "" {
		return nil, errors.New("runtime identity key snapshot: active signing key is unavailable")
	}
	keys := []delegationv1.VerificationKey{{
		SigningKeyID: s.Active.SigningKeyID,
		PublicKey:    append(ed25519.PublicKey(nil), s.Active.PrivateKey.Public().(ed25519.PublicKey)...),
		State:        delegationv1.KeyStateCurrent,
	}}
	seen := map[string]struct{}{s.Active.SigningKeyID: {}}
	for _, overlap := range s.Overlap {
		if overlap.SigningKeyID == "" || len(overlap.PublicKey) != ed25519.PublicKeySize {
			return nil, errors.New("runtime identity key snapshot: invalid overlap key")
		}
		if _, exists := seen[overlap.SigningKeyID]; exists {
			return nil, errors.New("runtime identity key snapshot: duplicate key id")
		}
		seen[overlap.SigningKeyID] = struct{}{}
		window := overlap.VerificationExpiresAt.Sub(overlap.SigningStoppedAt)
		if (overlap.Compromised && window != CompromisedKeyOverlap) || (!overlap.Compromised && window != PlannedOldKeyOverlap) {
			return nil, errors.New("runtime identity key snapshot: overlap violates P6-D")
		}
		state := delegationv1.KeyStateRetired
		if !overlap.Compromised && now.Before(overlap.VerificationExpiresAt) {
			state = delegationv1.KeyStateOverlap
		}
		keys = append(keys, delegationv1.VerificationKey{SigningKeyID: overlap.SigningKeyID, PublicKey: append(ed25519.PublicKey(nil), overlap.PublicKey...), State: state})
	}
	return keys, nil
}

func randomDelegationID() (string, error) {
	raw := make([]byte, 16)
	if _, err := rand.Read(raw); err != nil {
		return "", err
	}
	return "dlg_" + hex.EncodeToString(raw), nil
}

func sessionFailure(ctx context.Context, err error) error {
	if ctxErr := ctx.Err(); ctxErr != nil {
		return ctxErr
	}
	var statusError interface{ HTTPStatus() int }
	if errors.As(err, &statusError) && statusError.HTTPStatus() == http.StatusUnauthorized {
		return failure(semantic.FailureUnauthenticated)
	}
	return failure(semantic.FailureUnavailable)
}

func ownerFailure(ctx context.Context, err error, category semantic.FailureCategory) error {
	if ctxErr := ctx.Err(); ctxErr != nil {
		return ctxErr
	}
	if err == nil {
		return nil
	}
	return failure(category)
}

func failure(category semantic.FailureCategory) *semantic.Failure {
	return &semantic.Failure{Category: category}
}
