// internal/utils/encryption.go
package utils

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"io"
	"os"
)

// ✅ KRITERIA BASDAT: Keamanan Data - Enkripsi untuk Data Sensitif (5%)

var encryptionKey []byte

// InitEncryption inisialisasi encryption key dari environment
func InitEncryption() error {
	key := os.Getenv("ENCRYPTION_KEY")
	if key == "" {
		// Generate random key untuk development (TIDAK untuk production!)
		key = "32-byte-long-encryption-key!!" // 32 bytes untuk AES-256
	}

	if len(key) != 32 {
		return errors.New("encryption key must be exactly 32 bytes for AES-256")
	}

	encryptionKey = []byte(key)
	return nil
}

// EncryptString mengenkripsi string menggunakan AES-256-GCM
// Digunakan untuk data sensitif: password, NRP, phone, contact info
func EncryptString(plaintext string) (string, error) {
	if encryptionKey == nil {
		if err := InitEncryption(); err != nil {
			return "", err
		}
	}

	// Create AES cipher
	block, err := aes.NewCipher(encryptionKey)
	if err != nil {
		return "", err
	}

	// Create GCM mode (Galois/Counter Mode) - authenticated encryption
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// Generate nonce (number used once)
	nonce := make([]byte, gcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	// Encrypt and authenticate
	ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)

	// Encode to base64 untuk storage di database
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

// DecryptString mendekripsi string yang sudah dienkripsi
func DecryptString(encrypted string) (string, error) {
	if encryptionKey == nil {
		if err := InitEncryption(); err != nil {
			return "", err
		}
	}

	// Decode from base64
	ciphertext, err := base64.StdEncoding.DecodeString(encrypted)
	if err != nil {
		return "", err
	}

	// Create AES cipher
	block, err := aes.NewCipher(encryptionKey)
	if err != nil {
		return "", err
	}

	// Create GCM mode
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// Extract nonce
	nonceSize := gcm.NonceSize()
	if len(ciphertext) < nonceSize {
		return "", errors.New("ciphertext too short")
	}

	nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]

	// Decrypt and verify
	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
	if err != nil {
		return "", err
	}

	return string(plaintext), nil
}

// EncryptSensitiveFields helper untuk encrypt multiple fields
func EncryptSensitiveFields(fields map[string]string) (map[string]string, error) {
	encrypted := make(map[string]string)
	
	for key, value := range fields {
		if value == "" {
			encrypted[key] = ""
			continue
		}
		
		encValue, err := EncryptString(value)
		if err != nil {
			return nil, err
		}
		encrypted[key] = encValue
	}
	
	return encrypted, nil
}

// DecryptSensitiveFields helper untuk decrypt multiple fields
func DecryptSensitiveFields(fields map[string]string) (map[string]string, error) {
	decrypted := make(map[string]string)
	
	for key, value := range fields {
		if value == "" {
			decrypted[key] = ""
			continue
		}
		
		decValue, err := DecryptString(value)
		if err != nil {
			return nil, err
		}
		decrypted[key] = decValue
	}
	
	return decrypted, nil
}

// MaskSensitiveData untuk logging (mask sebagian data)
// Contoh: "081234567890" -> "0812****7890"
func MaskSensitiveData(data string) string {
	if len(data) <= 8 {
		return "****"
	}
	
	prefix := data[:4]
	suffix := data[len(data)-4:]
	
	return prefix + "****" + suffix
}

// ValidateEncryption test apakah encryption bekerja
func ValidateEncryption() error {
	testData := "test-sensitive-data-12345"
	
	encrypted, err := EncryptString(testData)
	if err != nil {
		return err
	}
	
	decrypted, err := DecryptString(encrypted)
	if err != nil {
		return err
	}
	
	if decrypted != testData {
		return errors.New("encryption validation failed: data mismatch")
	}
	
	return nil
}