// fikoyt-eklenti-imzala: bridge deposunun DISINDA calisir. Ozel anahtar bu koda ve bu depoya girmez.
//
//	-uret <dosya>                      yeni Ed25519 anahtari uretir (seed base64), acik anahtari yazar
//	-key <dosya> -eklenti -surum -dosya -cikti   manifest.json uretir ve imzalar
package main

import (
	"crypto/ed25519"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"sort"
	"strings"
)

type manifest struct {
	Anahtar string       `json:"anahtar"`
	Surum   string       `json:"surum"`
	Sha256  string       `json:"sha256"`
	Imza    string       `json:"imza"`
	Bicim   string       `json:"bicim"`
	Acilis  bool         `json:"acilis"`
	Izinler []izinTanimi `json:"izinler,omitempty"`
}

// izinTanimi: bridge/paket.go izinTanimi ile birebir ayni alanlar ve etiketler (ozet bu bicime bagli).
type izinTanimi struct {
	Anahtar  string   `json:"anahtar"`
	Baslik   string   `json:"baslik"`
	Aciklama string   `json:"aciklama"`
	Islemler []string `json:"islemler,omitempty"`
}

// izinOzeti: bridge/paket.go izinOzeti ile birebir ayni (anahtara gore sirali JSON'un SHA-256'si).
func izinOzeti(liste []izinTanimi) string {
	kopya := make([]izinTanimi, 0, len(liste))
	kopya = append(kopya, liste...)
	sort.Slice(kopya, func(i, j int) bool { return kopya[i].Anahtar < kopya[j].Anahtar })
	veri, _ := json.Marshal(kopya)
	ozet := sha256.Sum256(veri)
	return hex.EncodeToString(ozet[:])
}

func kontrol(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, "hata:", err)
		os.Exit(1)
	}
}

func main() {
	uret := flag.String("uret", "", "yeni anahtar dosyasi yolu")
	anahtarDosya := flag.String("key", "", "ozel anahtar dosyasi (base64 seed)")
	eklenti := flag.String("eklenti", "", "eklenti anahtari, ornek: ornek")
	surum := flag.String("surum", "1.0.0", "surum")
	dosya := flag.String("dosya", "", "plugin.exe yolu")
	cikti := flag.String("cikti", "", "manifest.json yolu")
	aciklama := flag.String("aciklama", "", "aciklama.json yolu: magaza aciklamasini imzalar (cikti: aciklama.imza.json)")
	acilis := flag.Bool("acilis", false, "acilista otomatik baslasin (kullanici kurulumda ayrica onaylar)")
	izinDosya := flag.String("izinler", "", "izin tanimlari JSON dosyasi (dizi). Verilirse v3 imza uretilir")
	flag.Parse()

	if *uret != "" {
		pub, priv, err := ed25519.GenerateKey(rand.Reader)
		kontrol(err)
		kontrol(os.WriteFile(*uret, []byte(base64.StdEncoding.EncodeToString(priv.Seed())), 0600))
		fmt.Println(base64.StdEncoding.EncodeToString(pub))
		return
	}

	seedB64, err := os.ReadFile(*anahtarDosya)
	kontrol(err)
	seed, err := base64.StdEncoding.DecodeString(strings.TrimSpace(string(seedB64)))
	kontrol(err)
	// 32 bayt: seed. 64 bayt: keygen'in yazdigi tam ozel anahtar (seed || acik).
	var priv ed25519.PrivateKey
	switch len(seed) {
	case ed25519.SeedSize:
		priv = ed25519.NewKeyFromSeed(seed)
	case ed25519.PrivateKeySize:
		priv = ed25519.PrivateKey(seed)
	default:
		kontrol(fmt.Errorf("anahtar uzunlugu gecersiz: %d", len(seed)))
	}

	if *aciklama != "" {
		ham, err := os.ReadFile(*aciklama)
		kontrol(err)
		aOzet := sha256.Sum256(ham)
		aOzetHex := hex.EncodeToString(aOzet[:])
		// Web (aciklama-dogrula.ts) ile birebir ayni format.
		imzaMetni := []byte("fikoyt-aciklama-v1\n" + *eklenti + "\n" + aOzetHex)
		out, err := json.MarshalIndent(map[string]string{"ozet": aOzetHex, "imza": base64.StdEncoding.EncodeToString(ed25519.Sign(priv, imzaMetni))}, "", "  ")
		kontrol(err)
		kontrol(os.WriteFile(*cikti, out, 0644))
		fmt.Println("aciklama imzasi yazildi:", *cikti)
		return
	}

	veri, err := os.ReadFile(*dosya)
	kontrol(err)
	ozet := sha256.Sum256(veri)
	ozetHex := hex.EncodeToString(ozet[:])

	// bridge/paket.go imzaliMetin ile birebir ayni format: v2 (izin dosyasi yoksa) ya da v3 (-izinler ile).
	bitAcilis := "0"
	if *acilis {
		bitAcilis = "1"
	}
	bicim := "v2"
	var izinler []izinTanimi
	metin := []byte("fikoyt-eklenti-v2\n" + *eklenti + "\n" + *surum + "\n" + strings.ToLower(ozetHex) + "\n" + bitAcilis)
	if *izinDosya != "" {
		ham, err := os.ReadFile(*izinDosya)
		kontrol(err)
		kontrol(json.Unmarshal(ham, &izinler))
		bicim = "v3"
		metin = []byte("fikoyt-eklenti-v3\n" + *eklenti + "\n" + *surum + "\n" + strings.ToLower(ozetHex) + "\n" + bitAcilis + "\n" + izinOzeti(izinler))
	}
	m := manifest{
		Anahtar: *eklenti,
		Surum:   *surum,
		Sha256:  ozetHex,
		Imza:    base64.StdEncoding.EncodeToString(ed25519.Sign(priv, metin)),
		Bicim:   bicim,
		Acilis:  *acilis,
		Izinler: izinler,
	}
	json_, err := json.MarshalIndent(m, "", "  ")
	kontrol(err)
	kontrol(os.WriteFile(*cikti, json_, 0644))
	fmt.Println("manifest yazildi:", *cikti)
}
