package ucan

import (
	"github.com/ipfs/go-cid"
	"code.sonr.org/go/ucan/pkg/policy"
)

// ValidationErrorCode represents UCAN validation error types.
// These codes match the TypeScript ValidationErrorCode type in src/ucan.ts.
type ValidationErrorCode string

const (
	ErrCodeExpired             ValidationErrorCode = "EXPIRED"
	ErrCodeNotYetValid         ValidationErrorCode = "NOT_YET_VALID"
	ErrCodeInvalidSignature    ValidationErrorCode = "INVALID_SIGNATURE"
	ErrCodePrincipalMisaligned ValidationErrorCode = "PRINCIPAL_MISALIGNMENT"
	ErrCodePolicyViolation     ValidationErrorCode = "POLICY_VIOLATION"
	ErrCodeRevoked             ValidationErrorCode = "REVOKED"
	ErrCodeInvalidProofChain   ValidationErrorCode = "INVALID_PROOF_CHAIN"
	ErrCodeUnknownCommand      ValidationErrorCode = "UNKNOWN_COMMAND"
	ErrCodeMalformedToken      ValidationErrorCode = "MALFORMED_TOKEN"
)

// ValidationError represents a UCAN validation failure.
type ValidationError struct {
	Code    ValidationErrorCode `json:"code"`
	Message string              `json:"message"`
	Details map[string]any      `json:"details,omitempty"`
}

func (e *ValidationError) Error() string {
	return e.Message
}

// NewValidationError creates a validation error with the given code and message.
func NewValidationError(code ValidationErrorCode, message string) *ValidationError {
	return &ValidationError{
		Code:    code,
		Message: message,
	}
}

// NewValidationErrorWithDetails creates a validation error with additional details.
func NewValidationErrorWithDetails(code ValidationErrorCode, message string, details map[string]any) *ValidationError {
	return &ValidationError{
		Code:    code,
		Message: message,
		Details: details,
	}
}

// Capability represents the semantically-relevant claim of a delegation.
// It combines subject, command, and policy into a single authorization unit.
type Capability struct {
	// Subject DID (resource owner) - nil for powerline delegations
	Subject string `json:"sub"`
	// Command being delegated
	Command string `json:"cmd"`
	// Policy constraints on invocation arguments
	Policy policy.Policy `json:"pol"`
}

// ValidationResult represents the outcome of UCAN validation.
type ValidationResult struct {
	Valid      bool             `json:"valid"`
	Capability *Capability      `json:"capability,omitempty"`
	Error      *ValidationError `json:"error,omitempty"`
}

// ValidationSuccess creates a successful validation result.
func ValidationSuccess(cap *Capability) *ValidationResult {
	return &ValidationResult{
		Valid:      true,
		Capability: cap,
	}
}

// ValidationFailure creates a failed validation result.
func ValidationFailure(err *ValidationError) *ValidationResult {
	return &ValidationResult{
		Valid: false,
		Error: err,
	}
}

// CryptoAlgorithm represents supported signature algorithms.
type CryptoAlgorithm string

const (
	AlgorithmEd25519   CryptoAlgorithm = "Ed25519"
	AlgorithmP256      CryptoAlgorithm = "P-256"
	AlgorithmSecp256k1 CryptoAlgorithm = "secp256k1"
)

// ExecutionResult represents the outcome of an invocation execution.
type ExecutionResult[T any, E any] struct {
	Ok  *T `json:"ok,omitempty"`
	Err *E `json:"err,omitempty"`
}

// IsSuccess returns true if the result is successful.
func (r *ExecutionResult[T, E]) IsSuccess() bool {
	return r.Ok != nil
}

// IsError returns true if the result is an error.
func (r *ExecutionResult[T, E]) IsError() bool {
	return r.Err != nil
}

// Success creates a successful execution result.
func Success[T any, E any](value T) *ExecutionResult[T, E] {
	return &ExecutionResult[T, E]{Ok: &value}
}

// Failure creates a failed execution result.
func Failure[T any, E any](err E) *ExecutionResult[T, E] {
	return &ExecutionResult[T, E]{Err: &err}
}

// ReceiptPayload represents the result of an invocation execution.
// This matches the TypeScript ReceiptPayload in src/ucan.ts.
type ReceiptPayload struct {
	// Executor DID
	Issuer string `json:"iss"`
	// CID of executed invocation
	Ran cid.Cid `json:"ran"`
	// Execution result
	Out *ExecutionResult[any, any] `json:"out"`
	// Effects - CIDs of Tasks to enqueue
	Effects []cid.Cid `json:"fx,omitempty"`
	// Optional metadata
	Meta map[string]any `json:"meta,omitempty"`
	// Issuance timestamp (Unix seconds)
	IssuedAt *int64 `json:"iat,omitempty"`
}

// RevocationPayload represents a UCAN revocation request.
// This matches the TypeScript RevocationPayload in src/ucan.ts.
type RevocationPayload struct {
	// Revoker DID - must be issuer in delegation chain
	Issuer string `json:"iss"`
	// Subject of delegation being revoked
	Subject string `json:"sub"`
	// Revocation command (always "/ucan/revoke")
	Command string `json:"cmd"`
	// Revocation arguments
	Args RevocationArgs `json:"args"`
	// Proof chain
	Proof []cid.Cid `json:"prf"`
	// Nonce
	Nonce []byte `json:"nonce"`
	// Expiration (Unix seconds or null)
	Expiration *int64 `json:"exp"`
}

// RevocationArgs contains the arguments for a revocation invocation.
type RevocationArgs struct {
	// CID of delegation to revoke
	UCAN cid.Cid `json:"ucan"`
}

// Task represents a subset of Invocation fields that uniquely determine work.
// The Task ID is the CID of these fields.
type Task struct {
	// Subject DID
	Subject string `json:"sub"`
	// Command to execute
	Command string `json:"cmd"`
	// Command arguments
	Args map[string]any `json:"args"`
	// Nonce for uniqueness
	Nonce []byte `json:"nonce"`
}

// --- Sonr-specific Types ---

// VaultCapability represents authorization for vault operations.
type VaultCapability struct {
	// VaultCID identifies the specific vault
	VaultCID string `json:"vault_cid"`
	// Operations allowed (read, write, sign, export, import, delete, admin)
	Operations []string `json:"operations"`
}

// DIDCapability represents authorization for DID operations.
type DIDCapability struct {
	// DIDPattern is a glob pattern matching allowed DIDs
	DIDPattern string `json:"did_pattern"`
	// Operations allowed (create, update, deactivate)
	Operations []string `json:"operations"`
}

// DWNCapability represents authorization for DWN operations.
type DWNCapability struct {
	// RecordType specifies the allowed record type
	RecordType string `json:"record_type"`
	// Operations allowed (read, write, delete)
	Operations []string `json:"operations"`
}

// AccountCapability represents authorization for account operations.
type AccountCapability struct {
	// ChainID specifies the blockchain
	ChainID string `json:"chain_id"`
	// Address specifies the account (or "*" for all)
	Address string `json:"address"`
	// Operations allowed
	Operations []string `json:"operations"`
}

// SealedToken represents a signed UCAN token with its CID and raw bytes.
type SealedToken struct {
	// CID is the content identifier of the sealed token
	CID cid.Cid `json:"cid"`
	// Data is the DAG-CBOR encoded envelope
	Data []byte `json:"data"`
	// Type indicates if this is a delegation or invocation
	Type string `json:"type"` // "delegation" or "invocation"
}

// SealedDelegation is a type alias for a sealed delegation token.
type SealedDelegation = SealedToken

// SealedInvocation is a type alias for a sealed invocation token.
type SealedInvocation = SealedToken

// ProofChain represents an ordered list of delegation CIDs.
// Ordered from leaf (matching invocation issuer) to root delegation.
type ProofChain []cid.Cid

// NewProofChain creates a new proof chain from CIDs.
func NewProofChain(cids ...cid.Cid) ProofChain {
	return ProofChain(cids)
}

// Add appends a CID to the proof chain.
func (p *ProofChain) Add(c cid.Cid) {
	*p = append(*p, c)
}

// IsEmpty returns true if the proof chain is empty.
func (p ProofChain) IsEmpty() bool {
	return len(p) == 0
}

// Root returns the root delegation CID (last in chain).
func (p ProofChain) Root() (cid.Cid, bool) {
	if len(p) == 0 {
		return cid.Cid{}, false
	}
	return p[len(p)-1], true
}

// Leaf returns the leaf delegation CID (first in chain).
func (p ProofChain) Leaf() (cid.Cid, bool) {
	if len(p) == 0 {
		return cid.Cid{}, false
	}
	return p[0], true
}
