package queries

import (
	"github.com/fiskerinc/cloud-services/pkg/common"
	s "github.com/fiskerinc/cloud-services/pkg/security"
	"github.com/go-pg/pg/v10/orm"
	"github.com/pkg/errors"
)

type SignedImagesInterface interface {
	Insert(SignedImage common.SignedImage) (orm.Result, error)
	SelectAll() ([]common.SignedImage, error)
	SelectBySupplier(email string) (common.SignedImage, error)
	DeleteSigningCert(supplier_cert common.SupplierSigningCert) (orm.Result, error)
	GetSigningCert(supplier string, keyCert string) (common.SupplierSigningCert, error)
	InsertSigningCert(supplier_cert common.SupplierSigningCert) (orm.Result, error)
}

type SignedImages struct {
	QueryBase
}

func (si *SignedImages) Insert(signedImage common.SignedImage) (orm.Result, error) {
	return si.resultWithStack(si.GetDBConn().Model(&signedImage).Insert())
}

// Selects all public keys and signatures
func (si *SignedImages) SelectAll() ([]common.SignedImage, error) {
	signatures := []common.SignedImage{}

	err := si.GetDBConn().Model(&signatures).Column("signature").Select()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	return signatures, nil
}

// Selects all public keys and signatures
func (si *SignedImages) SelectBySupplier(email string) (common.SignedImage, error) {
	signature := common.SignedImage{}

	err := si.GetDBConn().Model(&signature).Where("email = ?", email).Order("created_at desc").Limit(1).Select()
	if err != nil {
		return signature, errors.WithStack(err)
	}

	return signature, err
}

func (si *SignedImages) decryptSigningCert(cert *common.SupplierSigningCert) error {
	enc := s.Encrypt{}
	encryptor, err := enc.GetEncryptor()
	if err != nil {
		return err
	}

	if cert.PrivateCertEncrypted != nil {
		key, err := encryptor.DecryptChunk(cert.PrivateCertEncrypted.Bytes())
		if err != nil {
			return err
		}
		cert.PrivateCert.SetBytes(key)
	}

	return nil
}

func (si *SignedImages) GetSigningCert(supplier string, keyCert string) (common.SupplierSigningCert, error) {
	cert := common.SupplierSigningCert{
		Supplier: supplier,
		KeyCert:  keyCert,
	}
	err := si.GetDBConn().Model(&cert).WherePK().Limit(1).Select()
	if err != nil {
		return cert, errors.WithStack(err)
	}

	err = si.decryptSigningCert(&cert)

	return cert, err
}

func (si *SignedImages) InsertSigningCert(supplier_cert common.SupplierSigningCert) (orm.Result, error) {
	enc := s.Encrypt{}
	encryptor, err := enc.GetEncryptor()
	if err != nil {
		return nil, err
	}

	supplier_cert.PrivateCertEncrypted = encryptor.EncryptChunk([]byte(supplier_cert.PrivateCert))

	return si.insert(&supplier_cert)
}

func (si *SignedImages) DeleteSigningCert(supplier_cert common.SupplierSigningCert) (orm.Result, error) {
	return si.delete(&supplier_cert)
}
