package main

// Kayitli hesap profilleri: oturumu olan profiller listelenir ve her biri ayri ayri yonetilir.
// Yalnizca yerel arayuz (yerelIstek) kullanabilir; web bu uclari cagiramaz.

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

type profilBilgi struct {
	Anahtar      string `json:"anahtar"`
	KullaniciAdi string `json:"kullaniciAdi"`
}

// profilListesi: oturumu (cerezi) olan tum profilleri dondurur.
func profilListesi() ([]profilBilgi, error) {
	liste := []profilBilgi{}
	kok, err := veriKlasoru()
	if err != nil {
		return nil, err
	}
	girdiler, err := os.ReadDir(filepath.Join(kok, "profiller"))
	if err != nil {
		return liste, nil
	}
	for _, g := range girdiler {
		if !g.IsDir() || !profilAnahtarDesen.MatchString(g.Name()) {
			continue
		}
		veri, err := os.ReadFile(filepath.Join(kok, "profiller", g.Name(), "oturum.json"))
		if err != nil {
			continue
		}
		var k oturumKaydi
		if json.Unmarshal(veri, &k) != nil || len(k.Cerezler) == 0 {
			continue
		}
		liste = append(liste, profilBilgi{
			Anahtar:      g.Name(),
			KullaniciAdi: k.KullaniciAdi,
		})
	}
	return liste, nil
}

// profilListeHandler: GET /profiller
func profilListeHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "yalnizca GET", http.StatusMethodNotAllowed)
		return
	}
	if !yerelIstek(w, r) {
		return
	}
	liste, err := profilListesi()
	if err != nil {
		http.Error(w, "profiller okunamadi", http.StatusInternalServerError)
		return
	}
	yazJSON(w, http.StatusOK, map[string]any{"profiller": liste})
}

// profilEtkinleHandler: POST /profiller/etkinle  {"anahtar": "..."}
// Oturumu olan bir hesabi etkin yapar: hesabin verisi yuklenir, sunucu baglantisi acilir.
func profilEtkinleHandler(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 struct {
		Anahtar string `json:"anahtar"`
	}
	if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1024)).Decode(&istek); err != nil {
		http.Error(w, "gecersiz istek", http.StatusBadRequest)
		return
	}
	if !profilAnahtarDesen.MatchString(istek.Anahtar) {
		yazJSON(w, http.StatusBadRequest, map[string]any{"hata": "gecersiz profil anahtari"})
		return
	}
	if _, err := oturumOkuProfil(istek.Anahtar); err != nil {
		yazJSON(w, http.StatusBadRequest, map[string]any{"hata": "once bu hesaba giris yapin"})
		return
	}
	if err := etkinHesapEkle(istek.Anahtar); err != nil {
		yazJSON(w, http.StatusInternalServerError, map[string]any{"hata": "hesap etkinlestirilemedi"})
		return
	}
	if err := kuruluYukleProfil(istek.Anahtar); err != nil {
		olayLog("kurulu liste okunamadi (%s): %v", istek.Anahtar, err)
	}
	if err := izinleriYukleProfil(istek.Anahtar); err != nil {
		olayLog("izinler okunamadi (%s): %v", istek.Anahtar, err)
	}
	if err := dosyaIzinleriYukle(istek.Anahtar); err != nil {
		olayLog("dosya izinleri okunamadi (%s): %v", istek.Anahtar, err)
	}
	profilSoketBaslat(istek.Anahtar)
	izinDurumGonderProfil(istek.Anahtar)
	senkronTetikle()
	olayLog("hesap etkinlestirildi: %s", istek.Anahtar)
	yazJSON(w, http.StatusOK, map[string]any{"ok": true})
}

// profilCikar: hesabi bu bilgisayardan cikarir. Oturum (cerez) silinir. verisiniSil false ise
// profil klasoru (eslesmeler, izinler, ayarlar) saklanir ve hesap yeniden girildiginde geri gelir.
// Akis sirasi:
//  1. Sunucu cihazi kaldirir ("kaldir" ucu; kaydin sahibi dogrulanir). Baska hesabin cihaziysa
//     sunucu reddeder, yerel veriye dokunulmaz ve hata donulur.
//  2. Yerel izinler sifirlanir ve sunucu gorunumu tazelenir.
//  3. Bu profilin eklenti surecleri durdurulur ve soketi kapatilir; diger hesaplar etkilenmez.
//  4. Yerel dogrulama: verisiniSil true ise klasor, false ise yalnizca oturum silinir.
func profilCikar(anahtar string, verisiniSil bool) error {
	if !profilAnahtarDesen.MatchString(anahtar) {
		return fmt.Errorf("gecersiz profil anahtari")
	}
	kok, err := veriKlasoru()
	if err != nil {
		return err
	}
	if err := etkinHesapCikar(anahtar); err != nil {
		olayLog("etkin hesap listesi guncellenemedi (%s): %v", anahtar, err)
	}
	klasor := filepath.Join(kok, "profiller", anahtar)
	if _, err := os.Stat(klasor); err != nil {
		return fmt.Errorf("profil bulunamadi")
	}

	if err := cihazKaldirGonder(anahtar); err != nil {
		// Oturum yok veya sunucuya ulasilamiyorsa sunucuda zaten cihaz kaydi yok;
		// yerel temizlemeye devam et. Sunucu acikca reddediyorsa (baska hesabin cihazi)
		// hata dondur ve yerel veriye dokunma.
		if !cagriYerelHataMi(err) {
			olayLog("sunucu cihaz kaldirilamadi (%s): %v", anahtar, err)
			return err
		}
		olayLog("sunucu cihaz kaldirilmadi (gecici): (%s): %v", anahtar, err)
	}
	if err := izinSifirlaProfil(anahtar); err != nil {
		olayLog("yerel izinler sifirlanamadi (%s): %v", anahtar, err)
	}
	izinDurumGonderProfil(anahtar)

	if verisiniSil {
		if err := os.RemoveAll(klasor); err != nil {
			return err
		}
		if _, err := os.Stat(klasor); !os.IsNotExist(err) {
			return fmt.Errorf("profil klasoru silinemedi")
		}
	} else {
		oturumYolu, oturumErr := oturumYoluProfil(anahtar)
		if oturumErr != nil {
			return oturumErr
		}
		if err := os.Remove(oturumYolu); err != nil && !os.IsNotExist(err) {
			return err
		}
		if _, err := os.Stat(oturumYolu); !os.IsNotExist(err) {
			return fmt.Errorf("oturum silinemedi")
		}
		if _, err := os.Stat(klasor); err != nil {
			return fmt.Errorf("profil klasoru korunamadi")
		}
	}

	// Bu hesabin eklenti surecleri ve soketi kapatilir; diger hesaplar etkilenmez.
	ekSurecDurdurProfil(anahtar)
	if b := sokProfildeBaglanti(anahtar); b != nil {
		_ = b.conn.Close()
	}
	senkronTetikle()
	olayLog("hesap cikarildi: %s (veri silindi: %v)", anahtar, verisiniSil)
	return nil
}

// profilCikarHandler: POST /profiller/cikar  {"anahtar": "...", "verisiniSil": false}
func profilCikarHandler(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 struct {
		Anahtar     string `json:"anahtar"`
		VerisiniSil bool   `json:"verisiniSil"`
	}
	if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1024)).Decode(&istek); err != nil {
		http.Error(w, "gecersiz istek", http.StatusBadRequest)
		return
	}
	if err := profilCikar(istek.Anahtar, istek.VerisiniSil); err != nil {
		yazJSON(w, http.StatusBadRequest, map[string]any{"hata": err.Error()})
		return
	}
	yazJSON(w, http.StatusOK, map[string]any{"ok": true})
}
