package find

import (
	"fmt"
	"time"

	"git.mleku.dev/mleku/nostr/encoders/event"
	"git.mleku.dev/mleku/nostr/encoders/hex"
	"git.mleku.dev/mleku/nostr/interfaces/signer"
)

// CreateTransferProposal creates a complete transfer proposal with authorization from previous owner
func CreateTransferProposal(name string, prevOwnerSigner, newOwnerSigner signer.I) (*event.E, error) {
	// Normalize name
	name = NormalizeName(name)

	// Validate name
	if err := ValidateName(name); err != nil {
		return nil, fmt.Errorf("invalid name: %w", err)
	}

	// Get public keys
	prevOwnerPubkey := hex.Enc(prevOwnerSigner.Pub())
	newOwnerPubkey := hex.Enc(newOwnerSigner.Pub())

	// Create timestamp for the transfer
	timestamp := time.Now()

	// Sign the transfer authorization with previous owner's key
	prevSig, err := SignTransferAuth(name, newOwnerPubkey, timestamp, prevOwnerSigner)
	if err != nil {
		return nil, fmt.Errorf("failed to create transfer authorization: %w", err)
	}

	// Create the transfer proposal event signed by new owner
	proposal, err := NewRegistrationProposalWithTransfer(name, prevOwnerPubkey, prevSig, newOwnerSigner)
	if err != nil {
		return nil, fmt.Errorf("failed to create transfer proposal: %w", err)
	}

	return proposal, nil
}

// ValidateTransferProposal validates a transfer proposal against the current owner
func ValidateTransferProposal(proposal *RegistrationProposal, currentOwner string) error {
	// Check that this is a transfer action
	if proposal.Action != ActionTransfer {
		return fmt.Errorf("not a transfer action: %s", proposal.Action)
	}

	// Check that prev_owner is set
	if proposal.PrevOwner == "" {
		return fmt.Errorf("missing prev_owner in transfer proposal")
	}

	// Check that prev_sig is set
	if proposal.PrevSig == "" {
		return fmt.Errorf("missing prev_sig in transfer proposal")
	}

	// Verify that prev_owner matches current owner
	if proposal.PrevOwner != currentOwner {
		return fmt.Errorf("prev_owner %s does not match current owner %s",
			proposal.PrevOwner, currentOwner)
	}

	// Get new owner from proposal event
	newOwnerPubkey := hex.Enc(proposal.Event.Pubkey)

	// Verify the transfer authorization signature
	// Use proposal creation time as timestamp
	timestamp := time.Unix(proposal.Event.CreatedAt, 0)

	ok, err := VerifyTransferAuth(proposal.Name, newOwnerPubkey, proposal.PrevOwner,
		timestamp, proposal.PrevSig)
	if err != nil {
		return fmt.Errorf("transfer authorization verification failed: %w", err)
	}

	if !ok {
		return fmt.Errorf("invalid transfer authorization signature")
	}

	return nil
}

// PrepareTransferAuth prepares the transfer authorization data that needs to be signed
// This is a helper for wallets/clients that want to show what they're signing
func PrepareTransferAuth(name, newOwner string, timestamp time.Time) TransferAuthorization {
	return TransferAuthorization{
		Name:      NormalizeName(name),
		NewOwner:  newOwner,
		Timestamp: timestamp,
	}
}

// AuthorizeTransfer creates a transfer authorization signature
// This is meant to be used by the current owner to authorize a transfer to a new owner
func AuthorizeTransfer(name, newOwnerPubkey string, ownerSigner signer.I) (prevSig string, timestamp time.Time, err error) {
	// Normalize name
	name = NormalizeName(name)

	// Validate name
	if err := ValidateName(name); err != nil {
		return "", time.Time{}, fmt.Errorf("invalid name: %w", err)
	}

	// Create timestamp
	timestamp = time.Now()

	// Sign the authorization
	prevSig, err = SignTransferAuth(name, newOwnerPubkey, timestamp, ownerSigner)
	if err != nil {
		return "", time.Time{}, fmt.Errorf("failed to sign transfer auth: %w", err)
	}

	return prevSig, timestamp, nil
}

// CreateTransferProposalWithAuth creates a transfer proposal using a pre-existing authorization
// This is useful when the previous owner has already provided their signature
func CreateTransferProposalWithAuth(name, prevOwnerPubkey, prevSig string, newOwnerSigner signer.I) (*event.E, error) {
	// Normalize name
	name = NormalizeName(name)

	// Validate name
	if err := ValidateName(name); err != nil {
		return nil, fmt.Errorf("invalid name: %w", err)
	}

	// Create the transfer proposal event
	proposal, err := NewRegistrationProposalWithTransfer(name, prevOwnerPubkey, prevSig, newOwnerSigner)
	if err != nil {
		return nil, fmt.Errorf("failed to create transfer proposal: %w", err)
	}

	return proposal, nil
}

// VerifyTransferProposalSignature verifies both the event signature and transfer authorization
func VerifyTransferProposalSignature(proposal *RegistrationProposal) error {
	// Verify the event signature itself
	if err := VerifyEvent(proposal.Event); err != nil {
		return fmt.Errorf("invalid event signature: %w", err)
	}

	// If this is a transfer, verify the transfer authorization
	if proposal.Action == ActionTransfer {
		// Get new owner from proposal event
		newOwnerPubkey := hex.Enc(proposal.Event.Pubkey)

		// Use proposal creation time as timestamp
		timestamp := time.Unix(proposal.Event.CreatedAt, 0)

		// Verify transfer auth
		ok, err := VerifyTransferAuth(proposal.Name, newOwnerPubkey, proposal.PrevOwner,
			timestamp, proposal.PrevSig)
		if err != nil {
			return fmt.Errorf("transfer authorization verification failed: %w", err)
		}

		if !ok {
			return fmt.Errorf("invalid transfer authorization signature")
		}
	}

	return nil
}
