// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 bitcoinplugin

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"math/big"

	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
	"github.com/apache/incubator-milagro-dta/libs/documents"
	"github.com/apache/incubator-milagro-dta/pkg/common"
	"github.com/btcsuite/btcd/btcec"
	"github.com/pkg/errors"
)

func deriveFinalPrivateKey(s *Service, order documents.OrderDoc, beneficiariesSikeSK []byte, beneficiariesSeed []byte, beneficiaryIDDocumentCID string, nodeID string, signingBlsPK []byte) (string, error) {
	if beneficiaryIDDocumentCID != "" {
		//we are using the beneficiary specified in order Part 3
		beneficiaryBlob := order.OrderPart3.BeneficiaryEncryptedData

		//Decrypt the Envelope intented for the Beneficiary
		privateKeyPart1of1, err := adhocEncryptedEnvelopeDecode(s, beneficiariesSikeSK, beneficiaryBlob, beneficiaryIDDocumentCID, signingBlsPK)
		if err != nil {
			return "", err
		}
		//Calculate the final private key by Eliptical Key addition of both parts
		privateKeyPart2of2 := order.OrderDocument.OrderPart4.Secret

		finalPrivateKey, err := addPrivateKeys(privateKeyPart1of1, privateKeyPart2of2)

		if err != nil {
			return "", err
		}
		return finalPrivateKey, err
	}

	//we are using the beneficiary specified in the order part 1
	privateKeyPart2of2 := order.OrderDocument.OrderPart4.Secret
	// if order.OrderDocument.BeneficiaryCID != nodeID {
	// 	//need to forward this data to the beneficiary to complete redemption
	// 	return "", errors.New("Currently beneficiary must be the same as the Principal")
	// }
	//restore the Seed
	_, _, ecAddPrivateKey, err := cryptowallet.Bip44Address(beneficiariesSeed, cryptowallet.CoinTypeBitcoinMain, 0, 0, 0)
	if err != nil {
		return "", err
	}
	privateKeyPart1of1 := hex.EncodeToString(ecAddPrivateKey.Serialize())
	finalPrivateKey, err := addPrivateKeys(privateKeyPart1of1, privateKeyPart2of2)
	if err != nil {
		return "", err
	}
	return finalPrivateKey, err

}

func adhocEncryptedEnvelopeEncode(s *Service, nodeID string, beneficiaryIDDocumentCID string, order documents.OrderDoc, blsSK []byte) ([]byte, error) {
	//Regenerate the original Princaipal Priv Key based on Order
	if beneficiaryIDDocumentCID == "" {
		//beneficiaryIDDocumentCID is empty when it was passed in the Inital Deposit Order
		return nil, nil
	}
	seedHex, err := common.RetrieveSeed(s.Store, order.Reference)
	if err != nil {
		return nil, err
	}
	seedOrderModifier := order.OrderDocument.OrderPart2.PreviousOrderCID
	seed, err := hex.DecodeString(seedHex)
	if err != nil {
		return nil, err
	}
	concatenatedSeeds := append(seed, seedOrderModifier...)
	finalSeed := sha256.Sum256(concatenatedSeeds)
	finalSeedHex := hex.EncodeToString(finalSeed[:])
	privateKeyPart1of2, err := cryptowallet.RedeemSecret(finalSeedHex)
	if err != nil {
		return nil, err
	}
	beneficiaryIDDocument, err := common.RetrieveIDDocFromIPFS(s.Ipfs, beneficiaryIDDocumentCID)
	if err != nil {
		return nil, err
	}
	secretBody := &documents.SimpleString{Content: privateKeyPart1of2}
	header := &documents.Header{}
	recipients := map[string]*documents.IDDoc{
		beneficiaryIDDocumentCID: beneficiaryIDDocument,
	}
	docEnv, err := documents.Encode(nodeID, nil, secretBody, header, blsSK, recipients)
	if err != nil {
		return nil, err
	}
	return docEnv, err
}

func adhocEncryptedEnvelopeDecode(s *Service, sikeSK []byte, beneficiaryBlob []byte, beneficiaryIDDocumentCID string, signingBlsPK []byte) (string, error) {
	//Regenerate the original Principal Priv Key based on Order
	secretBody := &documents.SimpleString{}
	_, err := documents.Decode(beneficiaryBlob, "INTERNAL", sikeSK, beneficiaryIDDocumentCID, nil, secretBody, signingBlsPK)
	if err != nil {
		return "", err
	}
	return secretBody.Content, err
}

func generateFinalPubKey(s *Service, pubKeyPart2of2 string, order documents.OrderDoc) (string, string, error) {
	beneficiaryIDDocumentCID := order.OrderDocument.BeneficiaryCID
	coinType := order.Coin
	var pubKeyPart1of2 string

	if beneficiaryIDDocumentCID == "" {
		//There is no beneficiary ID so we do it all locally based on
		//Retrieve the Local Seed
		seedHex, err := common.RetrieveSeed(s.Store, order.Reference)
		if err != nil {
			return "", "", err
		}
		seedOrderModifier := order.OrderDocument.OrderPart2.PreviousOrderCID
		seed, err := hex.DecodeString(seedHex)
		if err != nil {
			return "", "", err
		}
		concatenatedSeeds := append(seed, seedOrderModifier...)
		finalSeed := sha256.Sum256(concatenatedSeeds)
		finalSeedHex := hex.EncodeToString(finalSeed[:])
		//Use HD Wallet to obtain the local Public Key
		pubKeyPart1of2, err = cryptowallet.RedeemPublicKey(finalSeedHex)

		if err != nil {
			return "", "", err
		}
	}

	if beneficiaryIDDocumentCID != "" {
		//There is a BeneficiaryID use it to generate the key
		//Get beneficiary's identity out of IPFS
		id := &documents.IDDoc{}
		rawDocI, err := s.Ipfs.Get(beneficiaryIDDocumentCID)
		if err != nil {
			return "", "", errors.Wrapf(err, "Read identity Doc")
		}
		err = documents.DecodeIDDocument(rawDocI, beneficiaryIDDocumentCID, id)
		if err != nil {
			return "", "", err
		}
		pubKeyPart1of2 = hex.EncodeToString(id.BeneficiaryECPublicKey)
	}

	finalPublicKey, err := addPublicKeys(pubKeyPart2of2, pubKeyPart1of2)

	if err != nil {
		return "", "", err
	}
	addressForPublicKey, err := addressForPublicKey(finalPublicKey, int(coinType))
	if err != nil {
		return "", "", err
	}
	return finalPublicKey, addressForPublicKey, nil

}

//AddPrivateKeys Perform eliptical key additon on 2 privates keys
func addPrivateKeys(key1 string, key2 string) (string, error) {
	curveOrder := new(big.Int)
	curveOrder.SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
	priv1 := new(big.Int)
	priv2 := new(big.Int)
	priv3 := new(big.Int)
	priv1.SetString(key1, 16)
	priv2.SetString(key2, 16)
	priv3.Add(priv1, priv2)
	if curveOrder.Cmp(priv3) == -1 {
		priv3.Sub(priv3, curveOrder)
	}
	priv4 := fmt.Sprintf("%064x", priv3)
	return priv4, nil
}

//AddPublicKeys Perform eliptical key addition on 2 public keys
func addPublicKeys(key1 string, key2 string) (string, error) {
	pub1Hex, err := hex.DecodeString(key1)
	if err != nil {
		return "", errors.Wrap(err, "Failed to hex decode String")
	}
	dpub1, err := btcec.ParsePubKey(pub1Hex, btcec.S256())
	if err != nil {
		return "", errors.Wrap(err, "Failed to Parse Public Key")
	}
	pub2Hex, err := hex.DecodeString(key2)
	if err != nil {
		return "", errors.Wrap(err, "Failed to hex decode String")
	}
	dpub2, err := btcec.ParsePubKey(pub2Hex, btcec.S256())
	if err != nil {
		return "", errors.Wrap(err, "Failed to Parse Public Key")
	}
	x, y := btcec.S256().Add(dpub1.X, dpub1.Y, dpub2.X, dpub2.Y)
	comp := fmt.Sprintf("04%064X%064X", x, y)
	compByte, err := hex.DecodeString(comp)
	if err != nil {
		return "", err
	}
	pubKey, err := btcec.ParsePubKey([]byte(compByte), btcec.S256())
	if err != nil {
		return "", err
	}
	pubKeyString := hex.EncodeToString(pubKey.SerializeCompressed())
	return pubKeyString, nil
}
