package src

import (
	"context"
	"fmt"
	"os"

	"encoding/base64"
	"encoding/binary"

	"github.com/coocood/freecache"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readpref"
	"golang.org/x/crypto/blake2s"
)

const salt = "ENVIRONMENT"

// 30m
const timeout = 1800

// 10m
const cacheSize = 10 * 1024 * 1024

var dbCollection *mongo.Collection
var dbDevices *mongo.Collection
var mongoClient *mongo.Client
var cache *freecache.Cache

func DbConnect() {
	mongoClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(getMongoURI()))

	if err != nil {
		panic(err)
	}

	if err := mongoClient.Ping(context.TODO(), readpref.Primary()); err != nil {
		panic(err)
	}
	db := mongoClient.Database("Environment")
	dbCollection = db.Collection("Main")
	dbDevices = db.Collection("Devices")
	cache = freecache.NewCache(cacheSize)
}

func GetDeviceKey(api uint64) ([]byte, error) {
	cacheKey := Uint64ToBytes(api)
	// Check the cache for the user
	val, err := cache.Get(cacheKey)
	if err == nil {
		return val, err
	} else {
		apiSigned := int64(api)
		filter := bson.D{{"ApiID", apiSigned}}
		var result bson.M
		err := dbDevices.FindOne(context.TODO(), filter).Decode(&result)
		if err != nil {
			return nil, err
		}

		key, err := DeriveKey(result["Passcode"].(string))
		fmt.Printf(base64.StdEncoding.EncodeToString(key))
		// We should cache this!
		_ = cache.Set(cacheKey, key, timeout)
		return key, err
	}
}

func Uint64ToBytes(num uint64) []byte {
	buf := make([]byte, 8)
	binary.BigEndian.PutUint64(buf, num)
	return buf
}

func DeriveKey(passcode string) ([]byte, error) {

	hash, err := blake2s.New256(nil)
	if err != nil {
		return nil, err
	}
	hash.Write([]byte(salt))
	hash.Write([]byte(passcode))

	fmt.Printf("SALT %s PASS %s\n", salt, passcode)

	return hash.Sum(nil), nil
}

func DbDisconnect() {
	err := mongoClient.Disconnect(context.TODO())
	if err != nil {
		panic(err)
	}
}

func getMongoURI() string {
	dbPath := os.Getenv("GIN_DB_PATH")

	if dbPath == "" {
		dbPath = "mongodb://192.168.0.159:27017"
	}

	return dbPath
}
