package util

import (
	"bytes"
	"encoding/hex"
	"hash/fnv"
	"io/ioutil"
	"log"

	secp256k1 "github.com/btcsuite/btcd/btcec"
	json "github.com/goccy/go-json"
	"github.com/kr/pretty"
)

// FromHex hex -> []byte
func FromHex(s string) ([]byte, error) {
	if len(s) > 1 {
		if s[0:2] == "0x" || s[0:2] == "0X" {
			s = s[2:]
		}
		if len(s)%2 == 1 {
			s = "0" + s
		}
		return hex.DecodeString(s)
	}
	return []byte{}, nil
}

// ToHex []byte -> hex
func ToHex(b []byte) string {
	hex := hex.EncodeToString(b)
	// Prefer output of "0x0" instead of "0x"
	if len(hex) == 0 {
		return ""
	}
	return hex
}

// ToHex []byte -> hex
func ToHexPrefix(b []byte) string {
	hex := hex.EncodeToString(b)
	// Prefer output of "0x0" instead of "0x"
	if len(hex) == 0 {
		return ""
	}
	return "0x" + hex
}

// ECDH Calculate a shared secret using elliptic curve Diffie-Hellman
func ECDH(priv *secp256k1.PrivateKey, pub *secp256k1.PublicKey) []byte {
	ecKey := &secp256k1.PublicKey{}
	ecKey.X, ecKey.Y = secp256k1.S256().ScalarMult(pub.X, pub.Y, priv.D.Bytes())
	return ecKey.SerializeCompressed()
}

func ReadFile(file string) ([]byte, error) {
	fileCont, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}

	return fileCont, nil
}

var Sprint = pretty.Sprint

// Format a JSON document to make comparison easier.
func FormatJSON(object interface{}) interface{} {
	var out bytes.Buffer
	switch content := object.(type) {
	case string:
		json.Indent(&out, []byte(content), "", "\t")
	default:
		jsonString, err := json.Marshal(object)
		if err != nil {
			log.Println("[ERROR] unable to marshal json:", err)
		}
		json.Indent(&out, []byte(jsonString), "", "\t")
	}

	return string(out.Bytes())
}

// var FormatPbJSON = grpcPretty.FormatJSON
// var ToPbJSON = grpcPretty.ToJSON

//"github.com/sanity-io/litter"
//"github.com/kr/pretty"

var (
	Marshal   = json.Marshal
	Unmarshal = json.Unmarshal
)

func Hash64(s []byte) uint64 {
	h := fnv.New64a()
	_, _ = h.Write(s)
	return h.Sum64()
}
