package main

// Eklenti yetkileri, iki katman:
//  1) Ana anahtar (Izinler): yalnizca yerel tepsi/ayar arayuzunden acilir/kapanir.
//  2) Site yetkisi: fikoyt.com eslesmesinin, bu bilgisayarda onaylanmis ve SURELI yetkisi.
// Bir eklenti ancak iki katman da aciksa ve hiz siniri asilmamissa calisir.

import (
	"encoding/json"
	"errors"
	"os"
	"path/filepath"
	"sync"
	"time"
)

const siteYetkiSuresi = 24 * time.Hour
const dakikaSiniri = 60

// eklentiYetkiAnahtarlari: paket anahtari -> site yetki anahtari. Tek kaynak: izin verme
// (izin-iste), genel cagri (/eklenti/cagir) ve ozel uclar ayni adi kullanir. Tabloda olmayan
// eklentilerde yetki anahtari paket anahtaridir.
var eklentiYetkiAnahtarlari = map[string]string{
	"everything": "everythingAra",
}

// yetkiAnahtari: bir eklenti anahtarinin site yetki anahtarini doner.
func yetkiAnahtari(paket string) string {
	if y, ok := eklentiYetkiAnahtarlari[paket]; ok {
		return y
	}
	return paket
}

type yetkiKaydi struct {
	Anahtar string    `json:"anahtar"`
	Eslesme string    `json:"eslesme"` // eslesmenin token ozeti
	Bitis   time.Time `json:"bitis"`
}

var (
	yetkiMu      sync.Mutex
	yetkiListesi []yetkiKaydi
	hizMu        sync.Mutex
	hizKaydi     = map[string][]time.Time{}
)

func yetkiDosyasi() (string, error) {
	klasor, err := veriKlasoru()
	if err != nil {
		return "", err
	}
	return filepath.Join(klasor, "bridge-yetki.json"), nil
}

func yetkiYukle() error {
	yol, err := yetkiDosyasi()
	if err != nil {
		return err
	}
	veri, err := os.ReadFile(yol)
	if errors.Is(err, os.ErrNotExist) {
		return nil
	}
	if err != nil {
		return err
	}
	var liste []yetkiKaydi
	if err := json.Unmarshal(veri, &liste); err != nil {
		return err
	}
	yetkiMu.Lock()
	yetkiListesi = suresiDolmayanlar(liste)
	yetkiMu.Unlock()
	return nil
}

func suresiDolmayanlar(liste []yetkiKaydi) []yetkiKaydi {
	now := time.Now()
	out := make([]yetkiKaydi, 0, len(liste))
	for _, k := range liste {
		if k.Bitis.After(now) {
			out = append(out, k)
		}
	}
	return out
}

// yetkiKaydetLocked: yetkiMu kilitliyken cagrilmali.
func yetkiKaydetLocked() error {
	yol, err := yetkiDosyasi()
	if err != nil {
		return err
	}
	yetkiListesi = suresiDolmayanlar(yetkiListesi)
	veri, err := json.MarshalIndent(yetkiListesi, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(yol, veri, 0o600)
}

// yetkiVer: bir site icin bir anahtara sureli yetki verir (ayni kayit varsa yenilenir).
func yetkiVer(anahtar, eslesme string, sure time.Duration) error {
	yetkiMu.Lock()
	defer yetkiMu.Unlock()
	kalan := yetkiListesi[:0]
	for _, k := range yetkiListesi {
		if !(k.Anahtar == anahtar && k.Eslesme == eslesme) {
			kalan = append(kalan, k)
		}
	}
	yetkiListesi = append(kalan, yetkiKaydi{Anahtar: anahtar, Eslesme: eslesme, Bitis: time.Now().Add(sure)})
	return yetkiKaydetLocked()
}

// yetkiGeriAl: eslesme "" ise anahtarin tum site yetkilerini, degilse yalnizca o sitenin yetkisini siler.
func yetkiGeriAl(anahtar, eslesme string) error {
	yetkiMu.Lock()
	defer yetkiMu.Unlock()
	kalan := yetkiListesi[:0]
	for _, k := range yetkiListesi {
		if k.Anahtar == anahtar && (eslesme == "" || k.Eslesme == eslesme) {
			continue
		}
		kalan = append(kalan, k)
	}
	yetkiListesi = kalan
	return yetkiKaydetLocked()
}

// eslesmeYetkileriniSil: bir eslesme kaldirildiginda o sitenin tum yetkileri de silinir.
func eslesmeYetkileriniSil(eslesme string) error {
	yetkiMu.Lock()
	defer yetkiMu.Unlock()
	kalan := yetkiListesi[:0]
	for _, k := range yetkiListesi {
		if k.Eslesme != eslesme {
			kalan = append(kalan, k)
		}
	}
	yetkiListesi = kalan
	return yetkiKaydetLocked()
}

// yetkiGecerliMi: bu site icin bu anahtarda suresi dolmamis bir yetki var mi?
func yetkiGecerliMi(anahtar, eslesme string) bool {
	yetkiMu.Lock()
	defer yetkiMu.Unlock()
	now := time.Now()
	for _, k := range yetkiListesi {
		if k.Anahtar == anahtar && k.Eslesme == eslesme && k.Bitis.After(now) {
			return true
		}
	}
	return false
}

// hizIzinVer: anahtar+site basina dakikada en fazla dakikaSiniri istek.
func hizIzinVer(anahtar, eslesme string) bool {
	hizMu.Lock()
	defer hizMu.Unlock()
	anahtarBirlesik := anahtar + "|" + eslesme
	simdi := time.Now()
	birDakikaOnce := simdi.Add(-time.Minute)
	kayit := hizKaydi[anahtarBirlesik][:0]
	for _, t := range hizKaydi[anahtarBirlesik] {
		if t.After(birDakikaOnce) {
			kayit = append(kayit, t)
		}
	}
	if len(kayit) >= dakikaSiniri {
		hizKaydi[anahtarBirlesik] = kayit
		return false
	}
	hizKaydi[anahtarBirlesik] = append(kayit, simdi)
	return true
}
