package main

// POST /eklenti/cagir (token gerekli). Kurulu bir eklentiyi calistirir.
// Kapi: kurulu ve etkin mi -> bu site icin sureli yetki var mi -> hiz siniri -> ayri surec.
// Web kurulu eklentinin dosyasina erisemez; yalnizca yapilandirilmis istek gonderir.
// "klasor-ac" ayri bir yetki kullanir: ilk seferde (ya da yetki yoksa) bu bilgisayarda
// onay istenir; ekranda klasor, dosya ve iznin kapsami gosterilir. Kullanici
// "bu sefer", "1 saat" ya da "kalici" secebilir.

import (
	"encoding/json"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

const klasorYetkiAnahtari = "klasor-ac"

type eklentiCagriIstegi struct {
	Anahtar string          `json:"anahtar"`
	Islem   string          `json:"islem"`
	Veri    json.RawMessage `json:"veri,omitempty"`
}

// kuruluEklentiYoluProfil: verilen profilin kurulu surumunun plugin.exe yolu.
func kuruluEklentiYoluProfil(profil, anahtar string) (string, error) {
	surum, ok := kuruluSurumProfil(profil, anahtar)
	if !ok {
		return "", errKuruluYok
	}
	klasor, err := veriKlasoru()
	if err != nil {
		return "", err
	}
	yol := filepath.Join(klasor, "eklentiler", anahtar, surum, "plugin.exe")
	if err := eklentiYoluGecerliMi(yol); err != nil {
		return "", err
	}
	if _, err := os.Stat(yol); err != nil {
		return "", err
	}
	return yol, nil
}

// klasorIzniAl: klasor acma icin yetki yoksa onay ister ve secilen sureye gore yetki kaydeder.
// Onay ekrani, acilacak klasoru ve secilen dosyayi gosterir. Donus: izin verildi mi ve
// (verilmediyse) hata mesaji.
func klasorIzniAl(profil, site string, veri json.RawMessage) (bool, string) {
	if yetkiGecerliMiProfil(profil, klasorYetkiAnahtari, site) {
		return true, ""
	}
	var v struct {
		Yol string `json:"yol"`
	}
	if err := json.Unmarshal(veri, &v); err != nil || v.Yol == "" {
		return false, "klasor yolu belirtilmedi"
	}
	bilgi := onayBilgi{
		baslik:   hesapBaslik(profil, "Klasör açılsın mı?"),
		aciklama: "Bir web sitesi bu bilgisayarda bir dosyanın bulunduğu klasörü Gezgin'de açmak istiyor.",
		ayrinti: []string{
			"Açılacak klasör: " + filepath.Dir(v.Yol),
			"Seçilen dosya: " + filepath.Base(v.Yol),
			"Klasör yalnızca Gezgin penceresinde gösterilir.",
			"Dosyanın içeriği okunmaz ve bilgisayardan dışarı gönderilmez.",
		},
		kapsam: "Bu izin yalnızca fikoyt.com üzerinden klasör açma işlemini kapsar; başka bir işlem için kullanılmaz.",
	}
	izin, sure, err := onayBekleSecenekli(bilgi)
	if err != nil || !izin {
		return false, onayHataMetni(err, izin)
	}
	switch sure {
	case sureSaat:
		_ = yetkiVerProfil(profil, klasorYetkiAnahtari, site, time.Hour)
	case sureKalici:
		_ = yetkiVerProfil(profil, klasorYetkiAnahtari, site, kaliciSure)
	}
	return true, ""
}

// eklentiIzniAl: site icin eklenti yetkisi yoksa bilgisayarda onay ister. Kullanici "bu sefer"
// secerse yalnizca bu istek icin izin verilir (kaydedilmez); "1 saat" ya da "kalici" secilirse
// site icin yetki kaydedilir. Donus: izin verildi mi ve (verilmediyse) hata mesaji.
func eklentiIzniAl(profil, site, anahtar, islem string) (bool, string) {
	bilgi := onayBilgi{
		baslik:   hesapBaslik(profil, "Eklenti işlemine izin verilsin mi?"),
		aciklama: "Bir web sitesi bu bilgisayardaki " + anahtar + " eklentisinde " + islem + " işlemi çalıştırmak istiyor.",
		ayrinti: []string{
			"Eklenti: " + anahtar,
			"İşlem: " + islem,
		},
		kapsam: "1 saat ya da kalıcı seçilirse bu site için verilir ve Ayarlar'dan geri alınabilir. Bu sefer seçilirse yalnızca bu istek için izin verilir.",
	}
	izin, sure, err := onayBekleSecenekli(bilgi)
	if err != nil || !izin {
		return false, onayHataMetni(err, izin)
	}
	switch sure {
	case sureSaat:
		_ = yetkiVerProfil(profil, yetkiAnahtari(anahtar), site, time.Hour)
	case sureKalici:
		_ = yetkiVerProfil(profil, yetkiAnahtari(anahtar), site, kaliciSure)
	}
	return true, ""
}

func kuruluEklentiCagirHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "yalnizca POST", http.StatusMethodNotAllowed)
		return
	}
	var istek eklentiCagriIstegi
	if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 64*1024)).Decode(&istek); err != nil {
		http.Error(w, "gecersiz istek", http.StatusBadRequest)
		return
	}
	if !anahtarDesen.MatchString(istek.Anahtar) || istek.Islem == "" || len(istek.Islem) > 64 {
		http.Error(w, "gecersiz istek", http.StatusBadRequest)
		return
	}
	profil := profilDe(r)
	site := tokenOzeti(r.Header.Get("X-Bridge-Token"))
	if !kuruluEtkinMiProfil(profil, istek.Anahtar) {
		olayLog("kurulu eklenti reddedildi (kapali ya da kurulu degil): %s", istek.Anahtar)
		http.Error(w, "eklenti etkin degil", http.StatusForbidden)
		return
	}
	if istek.Islem != "klasor-ac" && !yetkiGecerliMiProfil(profil, yetkiAnahtari(istek.Anahtar), site) {
		izin, mesaj := eklentiIzniAl(profil, site, istek.Anahtar, istek.Islem)
		if !izin {
			olayLog("kurulu eklenti reddedildi (izin verilmedi): %s: %s", istek.Anahtar, mesaj)
			http.Error(w, mesaj, http.StatusForbidden)
			return
		}
	}
	if !hizIzinVer(istek.Anahtar, site) {
		olayLog("kurulu eklenti hiz siniri asildi: %s", istek.Anahtar)
		http.Error(w, "cok fazla istek", http.StatusTooManyRequests)
		return
	}
	if istek.Islem == "klasor-ac" {
		izin, mesaj := klasorIzniAl(profil, site, istek.Veri)
		if !izin {
			olayLog("klasor acma reddedildi: %s", mesaj)
			http.Error(w, mesaj, http.StatusForbidden)
			return
		}
	}
	yol, err := kuruluEklentiYoluProfil(profil, istek.Anahtar)
	if err != nil {
		olayLog("kurulu eklenti yolu bulunamadi: %s: %v", istek.Anahtar, err)
		http.Error(w, "eklenti dosyasi bulunamadi", http.StatusInternalServerError)
		return
	}
	cikti, err := eklentiCagirVarsayilan(eklentiCagri{Profil: profil, Anahtar: istek.Anahtar, Yol: yol, Islem: istek.Islem, Veri: istek.Veri, Ayar: kayitliAyarProfil(profil, istek.Anahtar)})
	if err != nil {
		olayLog("kurulu eklenti calismadi: %s: %v", istek.Anahtar, err)
		http.Error(w, "eklenti calistirilamadi", http.StatusBadGateway)
		return
	}
	if eklentiParcaliMi(cikti.Veri) {
		// Parcali sonuc yalnizca sunucu (socket) yoluyla birlestirilir; bu yerel HTTP yolu kabul edemez.
		olayLog("kurulu eklenti sonucu cok buyuk (parcali), HTTP yolu kabul etmiyor: %s", istek.Anahtar)
		http.Error(w, "sonuc cok buyuk", http.StatusBadGateway)
		return
	}
	olayLog("kurulu eklenti cagrildi: %s", istek.Anahtar)
	yazJSON(w, http.StatusOK, cikti)
}
