package main

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

// Izinler: her yetki ayri onaylanir ve varsayilan KAPALIDIR.
// Izin degisikligi yalnizca yerel tepsi arayuzunden yapilir (bu dosyada web'den
// yazan uc YOKTUR).
type Izinler struct {
	EverythingAra      bool  `json:"everythingAra"`
	CatiaAc            bool  `json:"catiaAc"`
	UsbBaglanti        bool  `json:"usbBaglanti"`
	DosyaYonetimiBitis int64 `json:"dosyaYonetimiBitis"`
}

var (
	izinMu sync.RWMutex
	// izinler: profil anahtarina gore izinler. Bos anahtar: profil secilmemis (kok klasor).
	izinler = map[string]Izinler{}
)

// izinDosyasiProfil: verilen profilin izin dosyasi. Bos anahtar: kok klasor.
func izinDosyasiProfil(anahtar string) (string, error) {
	var klasor string
	var err error
	if anahtar == "" {
		klasor, err = veriKlasoru()
	} else {
		klasor, err = profilKlasoru(anahtar)
	}
	if err != nil {
		return "", err
	}
	return filepath.Join(klasor, "bridge-izin.json"), nil
}

// izinDosyasi: aktif profilin izin dosyasi.

// izinleriYukleProfil: verilen profilin izinlerini diskten okur. Dosya yoksa hepsi kapali.
func izinleriYukleProfil(anahtar string) error {
	yol, err := izinDosyasiProfil(anahtar)
	if err != nil {
		return err
	}
	veri, err := os.ReadFile(yol)
	if errors.Is(err, os.ErrNotExist) {
		izinMu.Lock()
		izinler[anahtar] = Izinler{}
		izinMu.Unlock()
		return nil
	}
	if err != nil {
		return err
	}
	var y Izinler
	if err := json.Unmarshal(veri, &y); err != nil {
		return err
	}
	izinMu.Lock()
	izinler[anahtar] = y
	izinMu.Unlock()
	return nil
}

// izinleriKaydetProfil: verilen profilin izinlerini bellege alir ve diske yazar.
func izinleriKaydetProfil(anahtar string, y Izinler) error {
	yol, err := izinDosyasiProfil(anahtar)
	if err != nil {
		return err
	}
	veri, err := json.MarshalIndent(y, "", "  ")
	if err != nil {
		return err
	}
	izinMu.Lock()
	izinler[anahtar] = y
	izinMu.Unlock()
	return os.WriteFile(yol, veri, 0o600)
}

// izinOkuProfil: verilen profilin izinleri (bellekten). Bilinmeyen profil: hepsi kapali.
func izinOkuProfil(anahtar string) Izinler {
	izinMu.RLock()
	defer izinMu.RUnlock()
	return izinler[anahtar]
}

// izinlerHandler: yalnizca okuma. Degisiklik tepsi arayuzunden yapilir.
func izinlerHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "yalnizca GET", http.StatusMethodNotAllowed)
		return
	}
	yazJSON(w, http.StatusOK, izinOkuProfil(profilDe(r)))
}

// Acik: anahtara gore izin durumu. Bilinmeyen anahtar kapali sayilir.
func (y Izinler) Acik(anahtar string) bool {
	switch anahtar {
	case "everythingAra":
		return y.EverythingAra
	case "catiaAc":
		return y.CatiaAc
	case "usb":
		return y.UsbBaglanti
	case "dosyaYonetimi":
		return y.DosyaYonetimiBitis > time.Now().Unix()
	}
	return false
}

// Ayarla: anahtarin izin degerini degistirir (bilinmeyen anahtar yok sayilir).
// dosyaYonetimi icin true kalici (yaklasik 100 yil) olarak kaydedilir; sureli izin izinOnayla/izinKaydetOnay ile yazilir.
func (y *Izinler) Ayarla(anahtar string, deger bool) {
	switch anahtar {
	case "everythingAra":
		y.EverythingAra = deger
	case "catiaAc":
		y.CatiaAc = deger
	case "usb":
		y.UsbBaglanti = deger
	case "dosyaYonetimi":
		if deger {
			y.DosyaYonetimiBitis = time.Now().Add(kaliciSure).Unix()
		} else {
			y.DosyaYonetimiBitis = 0
		}
	}
}

// izinOnayla: yerel onay ekranini acar. dosyaYonetimi secenekli (sure secilir); digerleri iki dugmeli.
func izinOnayla(anahtar, baslik, aciklama string) (bool, string, error) {
	if anahtar == "dosyaYonetimi" {
		return onayBekleSecenekli(onayBilgi{baslik: baslik, aciklama: aciklama})
	}
	onay, err := onayBekle(baslik, aciklama)
	return onay, sureBuSefer, err
}

// izinKaydetOnayProfil: onaylanan izni verilen profil icin kaydeder.
func izinKaydetOnayProfil(profil, anahtar, sure string) (bool, error) {
	y := izinOkuProfil(profil)
	if anahtar == "dosyaYonetimi" {
		bitis, ok := secimBitisi(sure, time.Now())
		if !ok {
			return false, nil
		}
		y.DosyaYonetimiBitis = bitis
	} else {
		y.Ayarla(anahtar, true)
	}
	if err := izinleriKaydetProfil(profil, y); err != nil {
		return false, err
	}
	olayLog("izin yerelde onaylandı: %s (%s) [%s]", anahtar, sure, profil)
	izinDurumGonderProfil(profil)
	return true, nil
}
