package crypt

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"com.sismedika.com.absensi/pkg/config"
	"golang.org/x/crypto/bcrypt"
)

// openssl genrsa -out private.pem 1024
// openssl rsa -in private.pem -outform PEM -pubout out public.pem
func EncryptPassword(password string) (string, error) {
	pemData, err := ioutil.ReadFile(config.Data.Get("privatekey"))
	if err != nil {
		log.Printf("read key file: %s", err)
		return "", fmt.Errorf(("INTERNAL_SERVER_ERROR"))
	}
	block, _ := pem.Decode(pemData)
	if block == nil {
		log.Printf("bad key data: %s", "not PEM-encoded")
		return "", fmt.Errorf(("INTERNAL_SERVER_ERROR"))
	}
	if got, want := block.Type, "RSA PRIVATE KEY"; got != want {
		log.Printf("unknown key type %q, want %q", got, want)
		return "", fmt.Errorf(("INTERNAL_SERVER_ERROR"))
	}
	// Decode the RSA private key
	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		log.Printf("bad private key: %s", err)
		return "", fmt.Errorf(("INTERNAL_SERVER_ERROR"))
	}

	passEncrypted, err := rsa.EncryptPKCS1v15(rand.Reader, &priv.PublicKey, []byte(password))
	if err != nil {
		log.Printf("decrypt: %s\n", err)
		return "", fmt.Errorf(("DECRYPTION_FAILED"))
	}

	return base64.StdEncoding.EncodeToString(passEncrypted), nil
}

func DecryptPassword(passEncoded string) ([]byte, error) {
	/// decrypt password
	/// openssl genrsa -traditional -out private.pem 1024
	/// openssl rsa -in private.pem -outform PEM -pubout -out public.pem
	pemData, err := ioutil.ReadFile(config.Data.Get("privatekey"))
	if err != nil {
		log.Printf("read key file: %s", err)
		return nil, fmt.Errorf(("INTERNAL_SERVER_ERROR"))
	}
	block, _ := pem.Decode(pemData)
	if block == nil {
		log.Printf("bad key data: %s", "not PEM-encoded")
		return nil, fmt.Errorf(("INTERNAL_SERVER_ERROR"))
	}
	if got, want := block.Type, "RSA PRIVATE KEY"; got != want {
		log.Printf("unknown key type %q, want %q", got, want)
		return nil, fmt.Errorf(("INTERNAL_SERVER_ERROR"))
	}
	// Decode the RSA private key
	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		log.Printf("bad private key: %s", err)
		return nil, fmt.Errorf(("INTERNAL_SERVER_ERROR"))
	}

	var passDecrypted []byte
	var passDecoded []byte
	passDecoded, err = base64.StdEncoding.DecodeString(passEncoded)
	if err != nil {
		log.Printf("base64 decode: %s\n", err)
		return nil, fmt.Errorf(("BASE64_DECODE_FAILED"))
	}

	passDecrypted, err = rsa.DecryptPKCS1v15(rand.Reader, priv, []byte(passDecoded))
	if err != nil {
		log.Printf("decrypt: %s\n", err)
		return nil, fmt.Errorf(("DECRYPTION_FAILED"))
	}

	return passDecrypted, nil
}

func CheckPasswordHash(hash, password string) bool {
	start := time.Now()
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	log.Printf("CompareHashAndPassword execution took %s", time.Since(start))
	return err == nil
}
