package primitives

import (
	"crypto/rand"
	"git.openprivacy.ca/cwtch.im/tapir/utils"
	torProvider "git.openprivacy.ca/openprivacy/connectivity/tor"
	"golang.org/x/crypto/ed25519"
)

// Identity is an encapsulation of Name, PrivateKey and other features
// that make up a Tapir client.
// The purpose of Identity is to prevent other classes directly accessing private key
// and to ensure the integrity of security-critical functions.
type Identity struct {
	Name   string
	edpk   *ed25519.PrivateKey
	edpubk *ed25519.PublicKey
}

// InitializeIdentity is a courtesy function for initializing a V3 Identity in-code.
func InitializeIdentity(name string, pk *ed25519.PrivateKey, pubk *ed25519.PublicKey) Identity {
	return Identity{name, pk, pubk}
}

// InitializeEphemeralIdentity generates a new ephemeral identity, the private key of this identity is provided in the response.
func InitializeEphemeralIdentity() (Identity, ed25519.PrivateKey) {
	epk, esk, _ := ed25519.GenerateKey(rand.Reader)
	ephemeralPublicKey := ed25519.PublicKey(epk)
	ephemeralPrivateKey := ed25519.PrivateKey(esk)
	ephemeralIdentity := InitializeIdentity("", &ephemeralPrivateKey, &ephemeralPublicKey)
	return ephemeralIdentity, ephemeralPrivateKey
}

// PublicKeyBytes returns the public key associated with this Identity in serializable-friendly
// format.
func (i *Identity) PublicKeyBytes() []byte {
	return *i.edpubk
}

// PublicKey returns the public key associated with this Identity
func (i *Identity) PublicKey() ed25519.PublicKey {
	return *i.edpubk
}

// EDH performs a diffie-hellman operation on this identities private key with the given public key.
func (i *Identity) EDH(key ed25519.PublicKey) ([]byte, error) {
	secret, err := utils.EDH(*i.edpk, key)
	return secret[:], err
}

// Hostname provides the onion address associated with this Identity.
func (i *Identity) Hostname() string {
	return torProvider.GetTorV3Hostname(*i.edpubk)
}

// Sign produces a signature for a given message attributable to the given identity
func (i *Identity) Sign(input []byte) []byte {
	return ed25519.Sign(*i.edpk, input)
}
