package protocol

import (
	"crypto/sha1"
	"crypto/sha512"
	"math/big"
)

// Curve25519 Prime: 2^255 - 19
var P *big.Int

func init() {
	P, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16)
}

// Ed25519 Y (Compressed) to Curve25519 (Montgomery) U
// u = (1 + y) / (1 - y)
func EdwardsToMontgomery(yBytes []byte) ([]byte, error) {
	// 1. Decode y (little endian, clamped?)
	// "The 32-byte public key is the 32-byte little-endian encoding of the Point."
	// High bit is sign of x (ignored for U-coord conv usually?).

	// Reverse bytes to big.Int
	y := new(big.Int).SetBytes(Reverse(yBytes))

	// Clear high bit?
	// Ed25519 compressed form: high bit of last byte is X sign.
	// y &= ~(1 << 255)
	bit255 := big.NewInt(1)
	bit255.Lsh(bit255, 255)
	if y.Cmp(bit255) >= 0 {
		y.Sub(y, bit255)
	}

	one := big.NewInt(1)

	// num = 1 + y
	num := new(big.Int).Add(one, y)
	num.Mod(num, P)

	// den = 1 - y
	den := new(big.Int).Sub(one, y)
	// Handle negative result for modular arithmetic
	if den.Sign() < 0 {
		den.Add(den, P)
	}
	den.Mod(den, P)

	// denInv
	denInv := new(big.Int).ModInverse(den, P)

	// u = num * denInv
	u := new(big.Int).Mul(num, denInv)
	u.Mod(u, P)

	// Encode u (32 bytes little endian)
	uBytes := u.Bytes()
	uBytesRev := Reverse(uBytes)

	// Pad to 32
	res := make([]byte, 32)
	copy(res, uBytesRev) // Copy into start (little endian usually means LSB at 0?)
	// Wait. BigInt Bytes() returns Big Endian.
	// Reverse(BigEndian) -> Little Endian.
	// If uBytes is shorter than 32, we need to pad ZEROS at the END (high bytes) in Little Endian.
	// e.g. Value 1. BigEndian: [1]. Reverse: [1].
	// Result [1, 0, 0, ...]

	return res, nil
}

func Reverse(b []byte) []byte {
	l := len(b)
	r := make([]byte, l)
	for i := 0; i < l; i++ {
		r[i] = b[l-1-i]
	}
	return r
}

// CalculateSharedSecret inputs:
// serverPubKey (Montgomery U, 32 bytes)
// clientPrivKey (Scalar, 32 bytes)
func CalculateSharedSecret(serverPub, clientPriv []byte) []byte {
	// Use x/crypto/curve25519
	// ScalarMult(dst, scalar, point)
	// Placeholder as logic is in handshake.go currently
	return nil
}

// Helper to expand hashes
func Sha1Array(data []byte) [20]byte {
	return sha1.Sum(data)
}
func Sha512Array(data []byte) [64]byte {
	return sha512.Sum512(data)
}
