package main

import (
	"crypto/ecdh"
	"crypto/ed25519"
	"crypto/rand"
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"path/filepath"

	"apiSign/internal/config"
	"apiSign/internal/crypto"
)

func main() {
	outDir := flag.String("out", "./demo", "output directory")
	agentURL := flag.String("agent-url", "http://127.0.0.1:8081/v1/execute", "agent endpoint URL used by kong-sim")
	antireplay := flag.Bool("antireplay", true, "enable anti-replay (nonce) checks")
	maxBody := flag.Int64("max-body", 1<<20, "max envelope body bytes")
	skewMs := flag.Int64("skew-ms", 5*60*1000, "max allowed clock skew (ms)")
	ttlMs := flag.Int64("ttl-ms", 60*1000, "default ttl (ms)")
	flag.Parse()

	if err := os.MkdirAll(*outDir, 0o755); err != nil {
		fatal(err)
	}

	kongSignPub, kongSignPriv, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		fatal(err)
	}
	agentSignPub, agentSignPriv, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		fatal(err)
	}

	kongEncPriv, err := ecdh.X25519().GenerateKey(rand.Reader)
	if err != nil {
		fatal(err)
	}
	agentEncPriv, err := ecdh.X25519().GenerateKey(rand.Reader)
	if err != nil {
		fatal(err)
	}

	kongCfg := config.KongConfig{
		ListenAddr:  ":8080",
		AgentURL:    *agentURL,
		ProtoHeader: "kong-agent-secure/1",
		SigningKey: config.KeyPair{
			KID:        "kong-sign-v1",
			PrivateB64: crypto.B64Encode(kongSignPriv),
			PublicB64:  crypto.B64Encode(kongSignPub),
		},
		DecryptKey: config.KeyPair{
			KID:        "kong-enc-v1",
			PrivateB64: crypto.B64Encode(kongEncPriv.Bytes()),
			PublicB64:  crypto.B64Encode(kongEncPriv.PublicKey().Bytes()),
		},
		AgentSignPub: config.PublicKey{
			KID:       "agent-sign-v1",
			PublicB64: crypto.B64Encode(agentSignPub),
		},
		AgentEncPub: config.PublicKey{
			KID:       "agent-enc-v1",
			PublicB64: crypto.B64Encode(agentEncPriv.PublicKey().Bytes()),
		},
		Limits: config.Limits{
			MaxBodyBytes:      *maxBody,
			MaxClockSkewMs:    *skewMs,
			DefaultTTLms:      *ttlMs,
			AntiReplayEnabled: *antireplay,
		},
	}

	agentCfg := config.AgentConfig{
		ListenAddr:  ":8081",
		ProtoHeader: "kong-agent-secure/1",
		SigningKey: config.KeyPair{
			KID:        "agent-sign-v1",
			PrivateB64: crypto.B64Encode(agentSignPriv),
			PublicB64:  crypto.B64Encode(agentSignPub),
		},
		DecryptKey: config.KeyPair{
			KID:        "agent-enc-v1",
			PrivateB64: crypto.B64Encode(agentEncPriv.Bytes()),
			PublicB64:  crypto.B64Encode(agentEncPriv.PublicKey().Bytes()),
		},
		KongSignPub: config.PublicKey{
			KID:       "kong-sign-v1",
			PublicB64: crypto.B64Encode(kongSignPub),
		},
		KongEncPub: config.PublicKey{
			KID:       "kong-enc-v1",
			PublicB64: crypto.B64Encode(kongEncPriv.PublicKey().Bytes()),
		},
		Limits: config.Limits{
			MaxBodyBytes:      *maxBody,
			MaxClockSkewMs:    *skewMs,
			DefaultTTLms:      *ttlMs,
			AntiReplayEnabled: *antireplay,
		},
	}

	writeJSON(filepath.Join(*outDir, "kong.json"), kongCfg)
	writeJSON(filepath.Join(*outDir, "agent.json"), agentCfg)

	fmt.Printf("wrote %s and %s\n", filepath.Join(*outDir, "kong.json"), filepath.Join(*outDir, "agent.json"))
}

func writeJSON(path string, v any) {
	b, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		fatal(err)
	}
	if err := os.WriteFile(path, b, 0o600); err != nil {
		fatal(err)
	}
}

func fatal(err error) {
	fmt.Fprintln(os.Stderr, "error:", err)
	os.Exit(1)
}
