// platform_crypto — Arcrun 平台內部 crypto primitive
//
// Actions:
//   generate_api_key — HMAC-SHA256(email, ENCRYPTION_KEY) → ak_{hex[:32]}
//   encrypt          — AES-GCM(plaintext, ENCRYPTION_KEY) → {encrypted, iv}（base64）
//   random_token     — crypto random bytes → hex string
//
// ENCRYPTION_KEY 由 host 持有，永不進入 WASM。
//
// Host imports:
//   u6u.crypto_hmac_sha256  — HMAC-SHA256(data, key=ENCRYPTION_KEY) → raw bytes
//   u6u.crypto_aes_encrypt  — AES-GCM(plaintext, key=ENCRYPTION_KEY) → encrypted_b64 + iv_b64
//   u6u.crypto_random_bytes — crypto-random bytes → hex string
//
//go:build tinygo

package main

import (
	"encoding/json"
	"io"
	"os"
	"strings"
	"unsafe"
)

// ── host function 宣告 ───────────────────────────────────────────────────────

// crypto_hmac_sha256(dataPtr, dataLen, outPtr, outLenPtr) → 0 成功
// key = host 的 ENCRYPTION_KEY，output = raw bytes（hex encode 由 WASM 做）
//
//go:wasmimport u6u crypto_hmac_sha256
func hostCryptoHmacSha256(
	dataPtr uintptr, dataLen uint32,
	outPtr uintptr, outLenPtr uintptr,
) uint32

// crypto_aes_encrypt(plaintextPtr, plaintextLen, outEncPtr, outEncLenPtr, outIvPtr, outIvLenPtr) → 0 成功
// output: encrypted（base64）放 outEnc，iv（base64）放 outIv
//
//go:wasmimport u6u crypto_aes_encrypt
func hostCryptoAesEncrypt(
	plaintextPtr uintptr, plaintextLen uint32,
	outEncPtr uintptr, outEncLenPtr uintptr,
	outIvPtr uintptr, outIvLenPtr uintptr,
) uint32

// crypto_random_bytes(numBytes, outPtr, outLenPtr) → 0 成功
// output: hex string
//
//go:wasmimport u6u crypto_random_bytes
func hostCryptoRandomBytes(
	numBytes uint32,
	outPtr uintptr, outLenPtr uintptr,
) uint32

// ── 型別 ─────────────────────────────────────────────────────────────────────

type Input struct {
	Action    string `json:"action"`
	Email     string `json:"email,omitempty"`
	Plaintext string `json:"plaintext,omitempty"`
	Bytes     int    `json:"bytes,omitempty"`
}

// ── main ─────────────────────────────────────────────────────────────────────

func main() {
	raw, err := io.ReadAll(os.Stdin)
	if err != nil {
		writeError("failed to read stdin: " + err.Error())
		return
	}

	var input Input
	if err := json.Unmarshal(raw, &input); err != nil {
		writeError("invalid input JSON: " + err.Error())
		return
	}

	switch input.Action {
	case "generate_api_key":
		if input.Email == "" {
			writeError("email 必填")
			return
		}
		sig, ok := hmacSha256([]byte(input.Email))
		if !ok {
			writeError("HMAC-SHA256 失敗")
			return
		}
		apiKey := "ak_" + hex(sig)[:32]
		out, _ := json.Marshal(map[string]interface{}{
			"success": true,
			"api_key": apiKey,
		})
		os.Stdout.Write(out)

	case "encrypt":
		if input.Plaintext == "" {
			writeError("plaintext 必填")
			return
		}
		encB64, ivB64, ok := aesEncrypt([]byte(input.Plaintext))
		if !ok {
			writeError("AES-GCM 加密失敗")
			return
		}
		out, _ := json.Marshal(map[string]interface{}{
			"success":   true,
			"encrypted": encB64,
			"iv":        ivB64,
		})
		os.Stdout.Write(out)

	case "random_token":
		n := input.Bytes
		if n <= 0 {
			n = 32
		}
		token, ok := randomBytes(uint32(n))
		if !ok {
			writeError("random bytes 失敗")
			return
		}
		out, _ := json.Marshal(map[string]interface{}{
			"success": true,
			"token":   token,
		})
		os.Stdout.Write(out)

	default:
		writeError("不支援的 action: " + input.Action)
	}
}

// ── helpers ───────────────────────────────────────────────────────────────────

func writeError(msg string) {
	out, _ := json.Marshal(map[string]interface{}{
		"success": false,
		"error":   msg,
	})
	os.Stdout.Write(out)
}

func hmacSha256(data []byte) ([]byte, bool) {
	if len(data) == 0 {
		return nil, false
	}
	outBuf := make([]byte, 64) // SHA-256 = 32 bytes raw
	var outLen uint32
	status := hostCryptoHmacSha256(
		uintptr(unsafe.Pointer(&data[0])), uint32(len(data)),
		uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)),
	)
	if status != 0 {
		return nil, false
	}
	return outBuf[:outLen], true
}

func aesEncrypt(plaintext []byte) (string, string, bool) {
	if len(plaintext) == 0 {
		return "", "", false
	}
	encBuf := make([]byte, 65536)
	ivBuf := make([]byte, 64)
	var encLen, ivLen uint32
	status := hostCryptoAesEncrypt(
		uintptr(unsafe.Pointer(&plaintext[0])), uint32(len(plaintext)),
		uintptr(unsafe.Pointer(&encBuf[0])), uintptr(unsafe.Pointer(&encLen)),
		uintptr(unsafe.Pointer(&ivBuf[0])), uintptr(unsafe.Pointer(&ivLen)),
	)
	if status != 0 {
		return "", "", false
	}
	return string(encBuf[:encLen]), string(ivBuf[:ivLen]), true
}

func randomBytes(n uint32) (string, bool) {
	outBuf := make([]byte, n*2+4) // hex = 2 chars per byte
	var outLen uint32
	status := hostCryptoRandomBytes(
		n,
		uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)),
	)
	if status != 0 {
		return "", false
	}
	return string(outBuf[:outLen]), true
}

// hex encodes raw bytes to lowercase hex string
func hex(b []byte) string {
	const hexChars = "0123456789abcdef"
	out := make([]byte, len(b)*2)
	for i, v := range b {
		out[i*2] = hexChars[v>>4]
		out[i*2+1] = hexChars[v&0xf]
	}
	return string(out)
}

// strings import 只為了 strings.Builder（interpolate 用，這裡不需要但 import 要保留給未來）
var _ = strings.Builder{}
