package main

// Yerel ayar sayfasi: http://127.0.0.1:7878/ayarlar
// Izinler ve eslesmeler yalnizca bu sayfadan degistirilebilir.
// Guvenlik:
//   - Sayfa ve degisiklik uclari, Origin basligi olan HER istegi reddeder
//     (bridge'in kendi sayfasi haric). Web sitesi bu uclara erisemez.
//   - Degisiklik istekleri, sayfaya gomulu, her acilista yeniden uretilen
//     CSRF token'ini ister (sabit zamanli karsilastirma).
//   - Sayfa yalnizca hesap girisi yapildiktan sonra acilir.

import (
	"crypto/rand"
	"crypto/subtle"
	"encoding/hex"
	"encoding/json"
	"net/http"
)

var csrfToken = yeniCsrfToken()

func yeniCsrfToken() string {
	b := make([]byte, 32)
	if _, err := rand.Read(b); err != nil {
		panic(err) // rastgele kaynak yoksa guvenli calisamaz
	}
	return hex.EncodeToString(b)
}

// yerelIstek: Origin yoksa (dogrudan gezinme) ya da bridge'in kendi sayfasindan geliyorsa izin verir.
func yerelIstek(w http.ResponseWriter, r *http.Request) bool {
	o := r.Header.Get("Origin")
	if o != "" && o != "http://"+dinleAdres && o != "http://localhost:7878" {
		http.Error(w, "yetkisiz kaynak", http.StatusForbidden)
		return false
	}
	return true
}

func csrfDogrula(w http.ResponseWriter, r *http.Request) bool {
	if subtle.ConstantTimeCompare([]byte(r.Header.Get("X-Csrf-Token")), []byte(csrfToken)) != 1 {
		http.Error(w, "gecersiz token", http.StatusForbidden)
		return false
	}
	return true
}

type izinDegisimIstegi struct {
	Profil  string `json:"profil"`
	Anahtar string `json:"anahtar"`
	Deger   bool   `json:"deger"`
}

func izinDegistirHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "yalnizca POST", http.StatusMethodNotAllowed)
		return
	}
	if !yerelIstek(w, r) || !csrfDogrula(w, r) {
		return
	}
	var istek izinDegisimIstegi
	if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1024)).Decode(&istek); err != nil {
		http.Error(w, "gecersiz istek", http.StatusBadRequest)
		return
	}
	p, ok := yerelHesap(w, istek.Profil)
	if !ok {
		return
	}
	y := izinOkuProfil(p)
	switch istek.Anahtar {
	case "everythingAra":
		y.EverythingAra = istek.Deger
	case "catiaAc":
		y.CatiaAc = istek.Deger
	case "usb":
		y.UsbBaglanti = istek.Deger
	default:
		http.Error(w, "bilinmeyen izin", http.StatusBadRequest)
		return
	}
	if err := izinleriKaydetProfil(p, y); err != nil {
		http.Error(w, "kaydedilemedi", http.StatusInternalServerError)
		return
	}
	izinDurumGonderProfil(p)
	if !istek.Deger {
		if err := yetkiGeriAlProfil(p, istek.Anahtar, ""); err != nil {
			olayLog("site yetkileri silinemedi: %v", err)
		}
	}
	yazJSON(w, http.StatusOK, y)
}

type eslesmeKaldirIstegi struct {
	Profil string `json:"profil"`
	Ozet   string `json:"ozet"`
}

// eslesmeKaldirHandler: bir eslesmeyi siler; o eslesmenin token'i artik gecersiz olur.
func eslesmeKaldirHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "yalnizca POST", http.StatusMethodNotAllowed)
		return
	}
	if !yerelIstek(w, r) || !csrfDogrula(w, r) {
		return
	}
	eslesmeKaldirCekirdek(w, r)
}

// eslesmeKaldirCekirdek: yerel arayuz disindan (test dahil) cagrilabilen is mantigi.
// Istegin hesabindaki eslesmeyi siler; baska hesaplara dokunmaz.
func eslesmeKaldirCekirdek(w http.ResponseWriter, r *http.Request) {
	var istek eslesmeKaldirIstegi
	if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1024)).Decode(&istek); err != nil || istek.Ozet == "" {
		http.Error(w, "gecersiz istek", http.StatusBadRequest)
		return
	}
	p, ok := yerelHesap(w, istek.Profil)
	if !ok {
		return
	}
	var kalan []eslesme
	silindi := false
	kaldirilanSite := ""
	for _, e := range eslesmeleriOkuProfil(p) {
		if !silindi && subtle.ConstantTimeCompare([]byte(e.TokenOzeti), []byte(istek.Ozet)) == 1 {
			silindi = true
			kaldirilanSite = e.Site
			continue
		}
		kalan = append(kalan, e)
	}
	if !silindi {
		http.Error(w, "eslesme bulunamadi", http.StatusNotFound)
		return
	}
	if err := eslesmeleriYazProfil(p, kalan); err != nil {
		http.Error(w, "kaydedilemedi", http.StatusInternalServerError)
		return
	}
	if err := eslesmeYetkileriniSilProfil(p, istek.Ozet); err != nil {
		olayLog("eslesme yetkileri silinemedi: %v", err)
	}
	// Sunucu kaydindaki izin gorunumu tazelenir; yoksa web bu siteyi hala "Hazir" gosterir.
	izinDurumGonderProfil(p)
	olayLog("eşleşme kaldırıldı: %s [%s]", kaldirilanSite, p)
	yazJSON(w, http.StatusOK, map[string]any{"ok": true})
}

// ayarlarIzinHandler: ayar sayfasinin guncel izin durumunu verir (GET ?profil=<anahtar>).
func ayarlarIzinHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "yalnizca GET", http.StatusMethodNotAllowed)
		return
	}
	if !yerelIstek(w, r) {
		return
	}
	p, ok := yerelHesap(w, r.URL.Query().Get("profil"))
	if !ok {
		return
	}
	yazJSON(w, http.StatusOK, izinOkuProfil(p))
}

// ayarlarGuncellemeHandler: otomatik guncelleme tercihini okur (GET) ya da degistirir (POST).
// Tercih yalnizca bu bilgisayarin yerel ayar sayfasindan degisir; web arayuzu degistiremez.
func ayarlarGuncellemeHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		if !yerelIstek(w, r) {
			return
		}
		yazJSON(w, http.StatusOK, guncellemeAyarOku())
	case http.MethodPost:
		if !yerelIstek(w, r) || !csrfDogrula(w, r) {
			return
		}
		var istek guncellemeAyar
		if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 256)).Decode(&istek); err != nil {
			http.Error(w, "gecersiz istek", http.StatusBadRequest)
			return
		}
		if err := guncellemeAyarYaz(istek); err != nil {
			http.Error(w, "kaydedilemedi", http.StatusInternalServerError)
			return
		}
		olayLog("otomatik guncelleme tercihi: %v", istek.Otomatik)
		bridgeSurumGonder()
		yazJSON(w, http.StatusOK, istek)
	default:
		http.Error(w, "yalnizca GET veya POST", http.StatusMethodNotAllowed)
	}
}
