// Package crypto provides quantum-resistant cryptographic primitives for the Synor blockchain.
package crypto

import (
	"encoding/base64"
	"encoding/hex"
	"fmt"
)

// ============================================================================
// Enumerations
// ============================================================================

// Network type for address generation
type Network string

const (
	NetworkMainnet Network = "mainnet"
	NetworkTestnet Network = "testnet"
	NetworkDevnet  Network = "devnet"
)

// FalconVariant selection
type FalconVariant string

const (
	Falcon512  FalconVariant = "falcon512"  // 128-bit security, ~690 byte signatures
	Falcon1024 FalconVariant = "falcon1024" // 256-bit security, ~1330 byte signatures
)

// SphincsVariant selection
type SphincsVariant string

const (
	Shake128s SphincsVariant = "shake128s" // 128-bit security, ~7.8KB signatures
	Shake192s SphincsVariant = "shake192s" // 192-bit security, ~16KB signatures
	Shake256s SphincsVariant = "shake256s" // 256-bit security, ~30KB signatures
)

// PqAlgorithm post-quantum algorithm selection
type PqAlgorithm string

const (
	Dilithium3  PqAlgorithm = "dilithium3"
	PqFalcon512 PqAlgorithm = "falcon512"
	PqFalcon1024 PqAlgorithm = "falcon1024"
	Sphincs128s PqAlgorithm = "sphincs128s"
	Sphincs192s PqAlgorithm = "sphincs192s"
	Sphincs256s PqAlgorithm = "sphincs256s"
)

// AlgorithmFamily classification
type AlgorithmFamily string

const (
	Classical AlgorithmFamily = "classical"
	Lattice   AlgorithmFamily = "lattice"
	HashBased AlgorithmFamily = "hash_based"
	Hybrid    AlgorithmFamily = "hybrid"
)

// ============================================================================
// Configuration Types
// ============================================================================

// Config for the crypto SDK
type Config struct {
	APIKey         string
	Endpoint       string
	Timeout        int // milliseconds
	Retries        int
	Debug          bool
	DefaultNetwork Network
}

// DefaultConfig returns a config with sensible defaults
func DefaultConfig(apiKey string) Config {
	return Config{
		APIKey:         apiKey,
		Endpoint:       "https://crypto.synor.io/v1",
		Timeout:        30000,
		Retries:        3,
		Debug:          false,
		DefaultNetwork: NetworkMainnet,
	}
}

// DerivationConfig for key derivation
type DerivationConfig struct {
	Salt         []byte
	Info         []byte
	OutputLength int
}

// PasswordDerivationConfig for password-based key derivation
type PasswordDerivationConfig struct {
	Salt         []byte
	Iterations   int
	OutputLength int
}

// DerivationPath BIP-44 style path
type DerivationPath struct {
	Account int
	Change  int
	Index   int
}

// CoinType for Synor in BIP-44
const CoinType = 0x5359

// String formats the derivation path
func (p DerivationPath) String() string {
	return fmt.Sprintf("m/44'/%d'/%d'/%d/%d", CoinType, p.Account, p.Change, p.Index)
}

// ExternalPath creates a path for external addresses
func ExternalPath(account, index int) DerivationPath {
	return DerivationPath{Account: account, Change: 0, Index: index}
}

// InternalPath creates a path for internal (change) addresses
func InternalPath(account, index int) DerivationPath {
	return DerivationPath{Account: account, Change: 1, Index: index}
}

// ============================================================================
// Key Types
// ============================================================================

// HybridPublicKey combines Ed25519 and Dilithium3
type HybridPublicKey struct {
	Ed25519   []byte // 32 bytes
	Dilithium []byte // ~1952 bytes
}

// Size returns the total key size
func (pk *HybridPublicKey) Size() int {
	return len(pk.Ed25519) + len(pk.Dilithium)
}

// SecretKey holds the master seed
type SecretKey struct {
	Ed25519Seed []byte // 32 bytes
	MasterSeed  []byte // 64 bytes
}

// FalconPublicKey for Falcon signatures
type FalconPublicKey struct {
	Variant FalconVariant
	Bytes   []byte
}

// FalconSecretKey for Falcon signatures
type FalconSecretKey struct {
	Variant FalconVariant
	Bytes   []byte
}

// SphincsPublicKey for SPHINCS+ signatures
type SphincsPublicKey struct {
	Variant SphincsVariant
	Bytes   []byte
}

// SphincsSecretKey for SPHINCS+ signatures
type SphincsSecretKey struct {
	Variant SphincsVariant
	Bytes   []byte
}

// ============================================================================
// Signature Types
// ============================================================================

// HybridSignature combines Ed25519 and Dilithium3 signatures
type HybridSignature struct {
	Ed25519   []byte // 64 bytes
	Dilithium []byte // ~3293 bytes
}

// Size returns the total signature size
func (s *HybridSignature) Size() int {
	return len(s.Ed25519) + len(s.Dilithium)
}

// ToBytes serializes the signature
func (s *HybridSignature) ToBytes() []byte {
	result := make([]byte, len(s.Ed25519)+len(s.Dilithium))
	copy(result, s.Ed25519)
	copy(result[len(s.Ed25519):], s.Dilithium)
	return result
}

// HybridSignatureFromBytes deserializes a signature
func HybridSignatureFromBytes(data []byte) (*HybridSignature, error) {
	if len(data) < 64 {
		return nil, fmt.Errorf("invalid signature length: %d", len(data))
	}
	return &HybridSignature{
		Ed25519:   data[:64],
		Dilithium: data[64:],
	}, nil
}

// FalconSignature for Falcon
type FalconSignature struct {
	Variant FalconVariant
	Bytes   []byte
}

// Size returns the signature size
func (s *FalconSignature) Size() int {
	return len(s.Bytes)
}

// SphincsSignature for SPHINCS+
type SphincsSignature struct {
	Variant SphincsVariant
	Bytes   []byte
}

// Size returns the signature size
func (s *SphincsSignature) Size() int {
	return len(s.Bytes)
}

// ============================================================================
// Keypair Types
// ============================================================================

// HybridKeypair combines Ed25519 and Dilithium3
type HybridKeypair struct {
	PublicKey *HybridPublicKey
	SecretKey *SecretKey
	addresses map[Network]string
}

// Address returns the address for a network
func (kp *HybridKeypair) Address(network Network) string {
	if kp.addresses == nil {
		return ""
	}
	return kp.addresses[network]
}

// FalconKeypair for Falcon signatures
type FalconKeypair struct {
	Variant   FalconVariant
	PublicKey *FalconPublicKey
	SecretKey *FalconSecretKey
}

// SphincsKeypair for SPHINCS+ signatures
type SphincsKeypair struct {
	Variant   SphincsVariant
	PublicKey *SphincsPublicKey
	SecretKey *SphincsSecretKey
}

// ============================================================================
// Mnemonic Types
// ============================================================================

// Mnemonic BIP-39 phrase
type Mnemonic struct {
	Phrase    string
	Words     []string
	WordCount int
	Entropy   []byte
}

// MnemonicValidation result
type MnemonicValidation struct {
	Valid bool
	Error string
}

// ============================================================================
// Address Types
// ============================================================================

// Address on the blockchain
type Address struct {
	Address    string
	Network    Network
	PubkeyHash []byte
}

// ============================================================================
// Hash Types
// ============================================================================

// Hash256 is a 256-bit hash
type Hash256 struct {
	Bytes []byte
	Hex   string
}

// NewHash256 creates a hash from bytes
func NewHash256(bytes []byte) Hash256 {
	return Hash256{
		Bytes: bytes,
		Hex:   hex.EncodeToString(bytes),
	}
}

// ============================================================================
// Negotiation Types
// ============================================================================

// AlgorithmCapabilities for negotiation
type AlgorithmCapabilities struct {
	PqAlgorithms []PqAlgorithm
	Classical    bool
	Hybrid       bool
	Preferred    *PqAlgorithm
}

// NegotiationPolicy for algorithm selection
type NegotiationPolicy struct {
	MinSecurityLevel int
	PreferCompact    bool
	AllowClassical   bool
	RequiredFamilies []AlgorithmFamily
}

// NegotiationResult after negotiation
type NegotiationResult struct {
	Algorithm     PqAlgorithm
	SecurityLevel int
	Family        AlgorithmFamily
	Hybrid        bool
}

// SessionParams after establishing a session
type SessionParams struct {
	Algorithm  PqAlgorithm
	SessionKey []byte
	ExpiresAt  *int64
}

// ============================================================================
// Error Types
// ============================================================================

// CryptoError represents a crypto operation error
type CryptoError struct {
	Message string
	Code    string
}

func (e *CryptoError) Error() string {
	if e.Code != "" {
		return fmt.Sprintf("%s (code: %s)", e.Message, e.Code)
	}
	return e.Message
}

// NewCryptoError creates a new error
func NewCryptoError(message, code string) *CryptoError {
	return &CryptoError{Message: message, Code: code}
}

// ============================================================================
// Constants
// ============================================================================

const (
	Ed25519PublicKeySize     = 32
	Ed25519SecretKeySize     = 32
	Ed25519SignatureSize     = 64
	Dilithium3PublicKeySize  = 1952
	Dilithium3SignatureSize  = 3293
	HybridSignatureSize      = 64 + 3293
	Falcon512SignatureSize   = 690
	Falcon512PublicKeySize   = 897
	Falcon1024SignatureSize  = 1330
	Falcon1024PublicKeySize  = 1793
	Sphincs128sSignatureSize = 7856
	Sphincs192sSignatureSize = 16224
	Sphincs256sSignatureSize = 29792
	MinPBKDF2Iterations      = 10000
	MinSaltLength            = 8
	DefaultEndpoint          = "https://crypto.synor.io/v1"
)

// AlgorithmSizes maps algorithms to their sizes
var AlgorithmSizes = map[string]struct {
	Signature int
	PublicKey int
}{
	"ed25519":    {64, 32},
	"dilithium3": {3293, 1952},
	"hybrid":     {3357, 1984},
	"falcon512":  {690, 897},
	"falcon1024": {1330, 1793},
	"sphincs128s": {7856, 32},
	"sphincs192s": {16224, 48},
	"sphincs256s": {29792, 64},
}

// ============================================================================
// Helper Functions
// ============================================================================

// EncodeBase64 encodes bytes to base64
func EncodeBase64(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}

// DecodeBase64 decodes base64 to bytes
func DecodeBase64(s string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(s)
}

// FalconSignatureSize returns the signature size for a variant
func FalconSignatureSize(variant FalconVariant) int {
	switch variant {
	case Falcon512:
		return Falcon512SignatureSize
	case Falcon1024:
		return Falcon1024SignatureSize
	default:
		return 0
	}
}

// FalconPublicKeySize returns the public key size for a variant
func FalconPublicKeySize(variant FalconVariant) int {
	switch variant {
	case Falcon512:
		return Falcon512PublicKeySize
	case Falcon1024:
		return Falcon1024PublicKeySize
	default:
		return 0
	}
}

// FalconSecurityLevel returns the security level for a variant
func FalconSecurityLevel(variant FalconVariant) int {
	switch variant {
	case Falcon512:
		return 128
	case Falcon1024:
		return 256
	default:
		return 0
	}
}

// SphincsSignatureSize returns the signature size for a variant
func SphincsSignatureSize(variant SphincsVariant) int {
	switch variant {
	case Shake128s:
		return Sphincs128sSignatureSize
	case Shake192s:
		return Sphincs192sSignatureSize
	case Shake256s:
		return Sphincs256sSignatureSize
	default:
		return 0
	}
}

// SphincsSecurityLevel returns the security level for a variant
func SphincsSecurityLevel(variant SphincsVariant) int {
	switch variant {
	case Shake128s:
		return 128
	case Shake192s:
		return 192
	case Shake256s:
		return 256
	default:
		return 0
	}
}
