package main

// Hesap bazli izin yonetimi sayfasi: aktif site izinleri, klasor izinleri, istek gecmisi
// ve iptal islemleri. Sayfa: /ayarlar/hesap/<anahtar>/izinler. Islemler yerel istek + CSRF ister.

import (
	"encoding/json"
	"fmt"
	"html"
	"net/http"
	"strings"
	"time"
)

// govdeAttr: istek govdesini HTML attribute icinde guvenle tasinacak JSON'a cevirir.
func govdeAttr(v any) string {
	veri, _ := json.Marshal(v)
	return html.EscapeString(string(veri))
}

func izinYonetimSayfasiYaz(w http.ResponseWriter, r *http.Request, anahtar string) {
	if r.Method != http.MethodGet {
		http.Error(w, "yalnızca GET", http.StatusMethodNotAllowed)
		return
	}
	if !yerelIstek(w, r) {
		return
	}
	if !herhangiOturumVar() {
		http.Redirect(w, r, "/giris", http.StatusSeeOther)
		return
	}
	if !profilAnahtarDesen.MatchString(anahtar) {
		http.NotFound(w, r)
		return
	}
	liste, err := profilListesi()
	if err != nil {
		http.Error(w, "hesaplar okunamadı", http.StatusInternalServerError)
		return
	}
	for _, p := range liste {
		if p.Anahtar == anahtar {
			yaz(w, izinYonetimHTML(p, csrfToken))
			return
		}
	}
	http.NotFound(w, r)
}

func izinYonetimHTML(p profilBilgi, token string) string {
	var b strings.Builder
	simdi := time.Now()
	b.WriteString(fmt.Sprintf(`<h1 class="sayfa-baslik">İzin yönetimi</h1><p class="aciklama">%s hesabına verilen izinler, klasör erişimleri ve istek geçmişi. İptal edilen izinler hemen geçersiz olur.</p>`,
		html.EscapeString(p.KullaniciAdi)))
	b.WriteString(`<meta name="hesap" content="` + html.EscapeString(p.Anahtar) + `">`)

	// Aktif site izinleri
	b.WriteString(`<section class="kart"><h2 class="kart-baslik">Aktif site izinleri</h2><p class="aciklama">Eşleşmiş sitelerin bu bilgisayardaki izinleri.</p>`)
	izinler := aktifSiteIzinleri(p.Anahtar)
	if len(izinler) == 0 {
		b.WriteString(`<div class="bos">Aktif site izni yok.</div>`)
	}
	for _, s := range izinler {
		b.WriteString(fmt.Sprintf(`<div class="satir"><div class="bilgi"><div class="baslik">%s</div><div class="alt">%s · Bitiş: %s</div></div><button class="dugme tehlike" data-post="/ayarlar/izin-iptal" data-govde="%s" data-yenile="1" data-onay="Bu izin iptal edilsin mi?">İptal et</button></div>`,
			html.EscapeString(s.Site), html.EscapeString(izinKisaAdi(s.Anahtar)), s.Bitis.Format("02.01.2006 15:04"),
			govdeAttr(map[string]string{"profil": p.Anahtar, "anahtar": s.Anahtar, "ozet": s.Ozet})))
	}
	b.WriteString(`</section>`)

	// Klasor izinleri
	b.WriteString(`<section class="kart"><h2 class="kart-baslik">Klasör izinleri</h2><p class="aciklama">Dosya yöneticisinin erişebildiği klasörler.</p>`)
	dy := dosyaIzinOku(p.Anahtar)
	gorunen := 0
	if dy.TamErisim > simdi.Unix() {
		gorunen++
		b.WriteString(fmt.Sprintf(`<div class="satir"><div class="bilgi"><div class="baslik">Tam erişim</div><div class="alt">Bitiş: %s</div></div><button class="dugme tehlike" data-post="/ayarlar/klasor-iptal" data-govde="%s" data-yenile="1" data-onay="Tam erişim kapatılsın mı?">Kapat</button></div>`,
			time.Unix(dy.TamErisim, 0).Format("02.01.2006 15:04"), govdeAttr(map[string]any{"profil": p.Anahtar, "tam": true})))
	}
	for _, k := range dy.Klasorler {
		if k.Bitis <= simdi.Unix() {
			continue
		}
		gorunen++
		var islemler []string
		for _, i := range k.Islemler {
			islemler = append(islemler, dosyaIslemAdlari[i])
		}
		b.WriteString(fmt.Sprintf(`<div class="satir"><div class="bilgi"><div class="baslik">%s</div><div class="alt">%s · Bitiş: %s</div></div><button class="dugme tehlike" data-post="/ayarlar/klasor-iptal" data-govde="%s" data-yenile="1" data-onay="Bu klasör izni kaldırılsın mı?">Kaldır</button></div>`,
			html.EscapeString(k.Kok), html.EscapeString(strings.Join(islemler, ", ")), time.Unix(k.Bitis, 0).Format("02.01.2006 15:04"),
			govdeAttr(map[string]any{"profil": p.Anahtar, "kok": k.Kok})))
	}
	if gorunen == 0 {
		b.WriteString(`<div class="bos">Aktif klasör izni yok.</div>`)
	}
	b.WriteString(`</section>`)

	// Istek gecmisi
	b.WriteString(`<section class="kart"><h2 class="kart-baslik">İstek geçmişi</h2><p class="aciklama">Hangi sitenin ne izni istediği ve sonucu. En son 100 kayıt gösterilir.</p>`)
	gecmis := izinGecmisiOku(p.Anahtar)
	if len(gecmis) == 0 {
		b.WriteString(`<div class="bos">Henüz izin isteği yok.</div>`)
	}
	for i, g := range gecmis {
		if i >= 100 {
			break
		}
		sinif, sonuc := sonucRozeti(g.Sonuc)
		site := g.Site
		if site == "" {
			site = "—"
		}
		hedef := izinKisaAdi(g.Anahtar)
		if g.Tur == "dosya" {
			hedef = "Dosya: " + g.Anahtar
		}
		b.WriteString(fmt.Sprintf(`<div class="satir"><div class="bilgi"><div class="baslik">%s</div><div class="alt">%s · %s</div></div><span class="rozet %s">%s</span></div>`,
			html.EscapeString(site), html.EscapeString(hedef), g.Zaman.Format("02.01.2006 15:04"), sinif, sonuc))
	}
	b.WriteString(`</section>`)

	// Tehlikeli islem
	b.WriteString(`<section class="kart"><h2 class="kart-baslik">Tüm izinleri iptal et</h2><p class="aciklama">Bu hesabın site izinleri, klasör erişimleri ve izin ayarları tek seferde kapatılır.</p>`)
	b.WriteString(fmt.Sprintf(`<div class="dugmeler"><button class="dugme tehlike" data-post="/ayarlar/izin-hepsi" data-govde="%s" data-yenile="1" data-onay="Bu hesabın tüm izinleri iptal edilsin mi?">Tüm izinleri iptal et</button></div></section>`,
		govdeAttr(map[string]string{"profil": p.Anahtar})))

	return sayfaKabugu(p.KullaniciAdi+" · İzinler", b.String(), token, "/ayarlar/hesap/"+p.Anahtar)
}

// sonucRozeti: gecmis sonucu icin rozet sinifi ve metni.
func sonucRozeti(s string) (string, string) {
	switch s {
	case "verildi":
		return "ok", "Verildi"
	case "reddedildi":
		return "uyari", "Reddedildi"
	case "iptal":
		return "", "İptal edildi"
	case "mesgul":
		return "uyari", "Meşgul"
	}
	return "uyari", "Hata"
}

type izinIptalIstegi struct {
	Profil  string `json:"profil"`
	Anahtar string `json:"anahtar"`
	Ozet    string `json:"ozet"`
}

// izinIptalHandler: bir site izninin tek yetkisini kapatir (POST /ayarlar/izin-iptal).
func izinIptalHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "yalnızca POST", http.StatusMethodNotAllowed)
		return
	}
	if !yerelIstek(w, r) || !csrfDogrula(w, r) {
		return
	}
	var istek izinIptalIstegi
	if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1024)).Decode(&istek); err != nil || istek.Ozet == "" || istek.Anahtar == "" {
		http.Error(w, "geçersiz istek", http.StatusBadRequest)
		return
	}
	p, ok := yerelHesap(w, istek.Profil)
	if !ok {
		return
	}
	site := siteAdiOzetten(p, istek.Ozet)
	if err := yetkiGeriAlProfil(p, istek.Anahtar, istek.Ozet); err != nil {
		http.Error(w, "kaydedilemedi", http.StatusInternalServerError)
		return
	}
	izinDurumGonderProfil(p)
	izinGecmisiEkle(p, izinGecmisKaydi{Tur: "site", Anahtar: istek.Anahtar, Site: site, Sonuc: "iptal"})
	olayLog("izin iptal edildi: %s (%s) [%s]", istek.Anahtar, site, p)
	yazJSON(w, http.StatusOK, map[string]any{"ok": true})
}

type klasorIptalIstegi struct {
	Profil string `json:"profil"`
	Kok    string `json:"kok"`
	Tam    bool   `json:"tam"`
}

// klasorIptalHandler: bir klasor iznini ya da tam erisimi kapatir (POST /ayarlar/klasor-iptal).
func klasorIptalHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "yalnızca POST", http.StatusMethodNotAllowed)
		return
	}
	if !yerelIstek(w, r) || !csrfDogrula(w, r) {
		return
	}
	var istek klasorIptalIstegi
	if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 4096)).Decode(&istek); err != nil || (!istek.Tam && istek.Kok == "") {
		http.Error(w, "geçersiz istek", http.StatusBadRequest)
		return
	}
	p, ok := yerelHesap(w, istek.Profil)
	if !ok {
		return
	}
	y := dosyaIzinOku(p)
	hedef := istek.Kok
	if istek.Tam {
		y.TamErisim = 0
		hedef = "tam erişim"
	} else {
		y.Klasorler = klasorIzniKaldir(y.Klasorler, istek.Kok)
	}
	if err := dosyaIzinleriKaydet(p, y); err != nil {
		http.Error(w, "kaydedilemedi", http.StatusInternalServerError)
		return
	}
	izinGecmisiEkle(p, izinGecmisKaydi{Tur: "dosya", Anahtar: hedef, Sonuc: "iptal"})
	olayLog("klasör izni kapatıldı: %s [%s]", hedef, p)
	yazJSON(w, http.StatusOK, map[string]any{"ok": true})
}

type profilIstegi struct {
	Profil string `json:"profil"`
}

// tumIzinIptalHandler: hesabin tum izinlerini kapatir (POST /ayarlar/izin-hepsi).
func tumIzinIptalHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "yalnızca POST", http.StatusMethodNotAllowed)
		return
	}
	if !yerelIstek(w, r) || !csrfDogrula(w, r) {
		return
	}
	var istek profilIstegi
	if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1024)).Decode(&istek); err != nil {
		http.Error(w, "geçersiz istek", http.StatusBadRequest)
		return
	}
	p, ok := yerelHesap(w, istek.Profil)
	if !ok {
		return
	}
	if err := tumIzinleriIptalEt(p); err != nil {
		http.Error(w, "kaydedilemedi", http.StatusInternalServerError)
		return
	}
	izinGecmisiEkle(p, izinGecmisKaydi{Tur: "site", Anahtar: "tümü", Sonuc: "iptal"})
	olayLog("tüm izinler iptal edildi [%s]", p)
	yazJSON(w, http.StatusOK, map[string]any{"ok": true})
}
