package device

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/json"
	"fmt"
)

// credentialsJSON is the JSON structure stored in encrypted device credentials.
// Must match the Python backend's encryption format.
type credentialsJSON struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

// DecryptCredentials decrypts AES-256-GCM encrypted credentials and returns the
// username and password stored within.
//
// The ciphertext format MUST match what Python's cryptography.hazmat.primitives.ciphers.aead.AESGCM
// produces when called as: nonce + AESGCM.encrypt(nonce, plaintext, None)
//
// Layout on disk:
//   - bytes [0:12]   — 12-byte random nonce (GCM standard)
//   - bytes [12:]    — ciphertext + 16-byte GCM authentication tag (appended by library)
//
// Go's cipher.AEAD.Open expects the GCM tag appended to the ciphertext, which is exactly
// how Python's cryptography library stores it, so the two are directly compatible.
func DecryptCredentials(ciphertext []byte, key []byte) (username, password string, err error) {
	if len(key) != 32 {
		return "", "", fmt.Errorf("encryption key must be 32 bytes, got %d", len(key))
	}
	if len(ciphertext) < 12+16 {
		return "", "", fmt.Errorf("ciphertext too short: need at least 28 bytes (12 nonce + 16 tag), got %d", len(ciphertext))
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		return "", "", fmt.Errorf("creating AES cipher: %w", err)
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", "", fmt.Errorf("creating GCM cipher: %w", err)
	}

	nonce := ciphertext[:12]
	encryptedData := ciphertext[12:]

	plaintext, err := gcm.Open(nil, nonce, encryptedData, nil)
	if err != nil {
		return "", "", fmt.Errorf("decrypting credentials (wrong key or tampered data): %w", err)
	}

	var creds credentialsJSON
	if err := json.Unmarshal(plaintext, &creds); err != nil {
		return "", "", fmt.Errorf("unmarshalling decrypted credentials JSON: %w", err)
	}

	return creds.Username, creds.Password, nil
}
