package crypto

import (
	"crypto/aes"
	"crypto/sha1" // #nosec
	"io"

	"github.com/go-faster/errors"

	"github.com/gotd/ige"

	"github.com/gotd/td/bin"
)

// DecryptExchangeAnswer decrypts messages created during key exchange.
func DecryptExchangeAnswer(data, key, iv []byte) (dst []byte, err error) {
	// Decrypting inner data.
	cipher, err := aes.NewCipher(key)
	if err != nil {
		return nil, errors.Wrap(err, "create aes cipher")
	}

	dataWithHash := make([]byte, len(data))
	// Checking length. Invalid length will lead to panic in CryptBlocks.
	if len(dataWithHash)%cipher.BlockSize() != 0 {
		return nil, errors.Errorf("invalid len of data_with_hash (%d %% 16 != 0)", len(dataWithHash))
	}
	ige.DecryptBlocks(cipher, iv, dataWithHash, data)

	dst = GuessDataWithHash(dataWithHash)
	if data == nil {
		// Most common cause of this error is invalid crypto implementation,
		// i.e. invalid keys are used to decrypt payload which lead to
		// decrypt failure, so data does not match sha1 with any padding.
		return nil, errors.New("guess data from data_with_hash")
	}

	return
}

// EncryptExchangeAnswer encrypts messages created during key exchange.
func EncryptExchangeAnswer(rand io.Reader, answer, key, iv []byte) (dst []byte, err error) {
	cipher, err := aes.NewCipher(key)
	if err != nil {
		return nil, errors.Wrap(err, "create aes cipher")
	}

	answerWithHash, err := DataWithHash(answer, rand)
	if err != nil {
		return nil, errors.Wrap(err, "get answer with hash")
	}

	dst = make([]byte, len(answerWithHash))
	ige.EncryptBlocks(cipher, iv, dst, answerWithHash)
	return
}

// NonceHash1 computes nonce_hash_1.
// See https://core.telegram.org/mtproto/auth_key#dh-key-exchange-complete.
func NonceHash1(newNonce bin.Int256, key Key) (r bin.Int128) {
	var buf []byte
	buf = append(buf, newNonce[:]...)
	buf = append(buf, 1)
	buf = append(buf, sha(key[:])[0:8]...)
	buf = sha(buf)[4:20]
	copy(r[:], buf)
	return
}

func sha(v []byte) []byte {
	h := sha1.Sum(v) // #nosec
	return h[:]
}
