// Copyright 2022-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package nkeys

import (
	"bytes"
	"reflect"
	"testing"
)

func testCurve(t *testing.T, kp KeyPair) {
	// Check seed
	seed, err := kp.Seed()
	if err != nil {
		t.Fatalf("Unexpected error retrieving seed: %v", err)
	}
	_, err = Decode(PrefixByteSeed, seed)
	if err != nil {
		t.Fatalf("Expected a proper seed string, got %s with err: %v", seed, err)
	}
	if pb, _, err := DecodeSeed(seed); err != nil || pb != PrefixByteCurve {
		t.Fatalf("Expected a proper seed string, got %s", seed)
	}

	// Check public key
	pub, err := kp.PublicKey()
	if err != nil {
		t.Fatalf("Received an error retrieving public key: %v", err)
	}
	if pub[0] != 'X' {
		t.Fatalf("Expected a prefix of 'X' but got %c", pub[0])
	}
	if !IsValidPublicCurveKey(pub) {
		t.Fatalf("Not a valid public curve key")
	}

	// Check private key
	private, err := kp.PrivateKey()
	if err != nil {
		t.Fatalf("Received an error retrieving private key: %v", err)
	}
	if private[0] != 'P' {
		t.Fatalf("Expected a prefix of 'P' but got %v", private[0])
	}

	// Seal
	rkp, _ := CreateCurveKeys()
	rpub, _ := rkp.PublicKey()

	msg := []byte("Hello xkeys!")
	encrypted, err := kp.Seal(msg, rpub)
	if err != nil {
		t.Fatalf("Received an error on Seal: %v", err)
	}

	decrypted, err := rkp.Open(encrypted, pub)
	if err != nil {
		t.Fatalf("Received an error on Open: %v", err)
	}
	if !bytes.Equal(decrypted, msg) {
		t.Fatalf("Expected %q to be %q", decrypted, msg)
	}
}

func TestCurveFromCreateCurveKeys(t *testing.T) {
	kp, err := CreateCurveKeys()
	if err != nil {
		t.Fatalf("Expected nil error on CreateCurveKeys, received %v", err)
	}
	if kp == nil {
		t.Fatal("Expected a non-nil curve key pair")
	}
	testCurve(t, kp)
}

func TestCurveFromCreatePair(t *testing.T) {
	kp, err := CreatePair(PrefixByteCurve)
	if err != nil {
		t.Fatalf("Expected nil error on CreatePair, received %v", err)
	}
	if kp == nil {
		t.Fatal("Expected a non-nil curve key pair")
	}
	testCurve(t, kp)
}

func TestCurveFromSeed(t *testing.T) {
	kp, _ := CreateCurveKeys()
	seed, _ := kp.Seed()

	nkp, err := FromCurveSeed(seed)
	if err != nil {
		t.Fatalf("Unexpected error deriving curve keypair: %v", err)
	}
	if !reflect.DeepEqual(kp.(*ckp), nkp.(*ckp)) {
		t.Fatal("Expected the curve pairs to be equal")
	}
	testCurve(t, nkp)
}

func TestCurveFromKeyPair(t *testing.T) {
	kp, _ := CreatePair(PrefixByteCurve)
	_, err := kp.Sign([]byte("hello"))
	if err == nil {
		t.Fatal("Expected sign to fail as it non supported operation")
	}
	if err != ErrInvalidCurveKeyOperation {
		t.Fatalf("Expected %v but got %v", ErrInvalidCurveKeyOperation, err)
	}
	err = kp.Verify([]byte("hello"), []byte("bad"))
	if err == nil {
		t.Fatal("Expected verify to fail as it is unsupported operation")
	}
	if err != ErrInvalidCurveKeyOperation {
		t.Fatalf("Expected %v but got %v", ErrInvalidCurveKeyOperation, err)
	}
}

func TestCurvePublic(t *testing.T) {
	kp, _ := CreatePair(PrefixByteCurve)
	_, err := kp.Sign([]byte("hello"))
	if err == nil {
		t.Fatal("Expected sign to fail as it non supported operation")
	}
	pk, err := kp.PublicKey()
	if err != nil {
		t.Fatalf("Unexpected public key error: %v", err)
	}
	pub, err := FromPublicKey(pk)
	if err != nil {
		t.Fatalf("Unexpected error when creating public key: %v", err)
	}
	_, err = pub.Open([]byte("hello"), "bad")
	if err != ErrCannotOpen {
		t.Fatalf("Expected %v but got %v", ErrCannotOpen, err)
	}
	_, err = pub.Seal([]byte("hello"), "bad")
	if err != ErrCannotSeal {
		t.Fatalf("Expected %v but got %v", ErrCannotSeal, err)
	}
	_, err = pub.SealWithRand([]byte("hello"), "bad", nil)
	if err != ErrCannotSeal {
		t.Fatalf("Expected %v but got %v", ErrCannotSeal, err)
	}
}

func TestCurvePublicEmptyBug(t *testing.T) {
	kp, _ := CreateCurveKeys()
	pub, _ := kp.PublicKey()

	rkp, _ := CreateCurveKeys()
	rpub, _ := rkp.PublicKey()

	msg := []byte("Empty public better not work!")
	encrypted, err := kp.Seal(msg, rpub)
	if err != nil {
		t.Fatalf("Received an error on Seal: %v", err)
	}
	decrypted, err := rkp.Open(encrypted, pub)
	if err != nil {
		t.Fatalf("Received an error on Open: %v", err)
	}
	if !bytes.Equal(decrypted, msg) {
		t.Fatalf("Expected %q to be %q", decrypted, msg)
	}
	// Check an empty pub key.
	var empty [curveKeyLen]byte
	epub, _ := Encode(PrefixByteCurve, empty[:])

	_, err = rkp.Open(encrypted, string(epub))
	if err == nil {
		t.Fatalf("Expected a failure with empty pub key")
	}
}
