package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"
)

// Canli test: gercek bir klasorde dosya islemlerini bastan sona dener (PC'de calistirilir).
// FIKOYT_DOSYA_KLASOR tanimli degilse atlanir. Calistirma ornegi:
//
//	set FIKOYT_DOSYA_KLASOR=D:\FikoYT-Test
//	go test -count=1 -run TestDosyaCanli -v .
//
// Olusturulan test dosyalari sonunda silinir. Klasor yoksa test durur (klasor olusturmaz).
func TestDosyaCanli(t *testing.T) {
	klasor := os.Getenv("FIKOYT_DOSYA_KLASOR")
	if klasor == "" {
		t.Skip("FIKOYT_DOSYA_KLASOR tanimli degil")
	}
	if _, err := os.Stat(klasor); err != nil {
		t.Fatalf("test klasoru yok: %v", err)
	}
	damga := time.Now().UnixNano()
	dosya := filepath.Join(klasor, fmt.Sprintf("fikoyt-canli-%d.txt", damga))
	kopya := filepath.Join(klasor, fmt.Sprintf("fikoyt-canli-kopya-%d.txt", damga))
	parcali := filepath.Join(klasor, fmt.Sprintf("fikoyt-canli-parcali-%d.bin", damga))
	t.Cleanup(func() {
		for _, y := range []string{dosya, kopya, parcali} {
			os.Remove(y)
			os.Remove(y + geciciEk)
		}
	})

	// 1) Tek parca yazma ve okuma
	if c := yaz2(veriIslem{Yol: dosya, Icerik: b64Test("merhaba"), Ilk: true, Bitti: true}); !c.Tamam {
		t.Fatalf("yazma basarisiz: %s", c.Hata)
	}
	if icerik := okuTest(t, dosya); icerik != "merhaba" {
		t.Fatalf("okuma yanlis: %q", icerik)
	}

	// 2) Ustune yazma: izin olmadan reddedilmeli, izinle yapilmali
	if c := yaz2(veriIslem{Yol: dosya, Icerik: b64Test("yeni"), Ilk: true, Bitti: true}); c.Tamam {
		t.Fatal("var olan dosyanin uzerine izinsiz yazildi")
	}
	if c := yaz2(veriIslem{Yol: dosya, Icerik: b64Test("yeni"), Ilk: true, Bitti: true, UzerineYaz: true}); !c.Tamam {
		t.Fatalf("izinli uzerine yazma basarisiz: %s", c.Hata)
	}
	if icerik := okuTest(t, dosya); icerik != "yeni" {
		t.Fatalf("uzerine yazma sonrasi icerik yanlis: %q", icerik)
	}

	// 3) Kopyalama ve hedef varken reddi
	if c := kopyala(veriIslem{Kaynak: dosya, Hedef: kopya}); !c.Tamam {
		t.Fatalf("kopyalama basarisiz: %s", c.Hata)
	}
	if icerik := okuTest(t, kopya); icerik != "yeni" {
		t.Fatalf("kopya icerigi yanlis: %q", icerik)
	}
	if c := kopyala(veriIslem{Kaynak: dosya, Hedef: kopya}); c.Tamam {
		t.Fatal("var olan hedefin uzerine kopyalandi")
	}

	// 4) Parcali yazma (900 KB, 300 KB parcalar) ve parcali okuma ile birebir karsilastirma
	veri := bytes.Repeat([]byte("0123456789abcdef"), 900*1024/16)
	const parca = 300 * 1024
	for ofset := 0; ofset < len(veri); ofset += parca {
		son := ofset + parca
		if son > len(veri) {
			son = len(veri)
		}
		c := yaz2(veriIslem{Yol: parcali, Icerik: base64.StdEncoding.EncodeToString(veri[ofset:son]), Ilk: ofset == 0, Bitti: son == len(veri)})
		if !c.Tamam {
			t.Fatalf("parca %d yazilamadi: %s", ofset, c.Hata)
		}
	}
	var okunan []byte
	for ofset := int64(0); ; {
		c := oku(veriIslem{Yol: parcali, Ofset: ofset, Uzunluk: maksParcaBoyutu})
		if !c.Tamam {
			t.Fatalf("parcali okuma basarisiz: %s", c.Hata)
		}
		v := c.Veri.(map[string]any)
		bayt, _ := base64.StdEncoding.DecodeString(v["icerik"].(string))
		okunan = append(okunan, bayt...)
		if v["bitti"].(bool) {
			break
		}
		ofset += int64(len(bayt))
	}
	if !bytes.Equal(okunan, veri) {
		t.Fatalf("parcali dosya eslesmedi: %d bayt yazildi, %d bayt okundu", len(veri), len(okunan))
	}

	// 5) Listeleme yeni dosyalari gostermeli
	c := listele(klasor)
	if !c.Tamam {
		t.Fatalf("listeleme basarisiz: %s", c.Hata)
	}
	gorulen := false
	for _, k := range c.Veri.(map[string]any)["kayitlar"].([]kayit) {
		if strings.EqualFold(k.Ad, filepath.Base(dosya)) {
			gorulen = true
		}
	}
	if !gorulen {
		t.Fatal("listelemede test dosyasi gorunmuyor")
	}

	// 6) Silme: dosyalar gitmeli; klasor silme reddedilmeli
	for _, y := range []string{kopya, dosya, parcali} {
		if c := sil(veriIslem{Yol: y}); !c.Tamam {
			t.Fatalf("silme basarisiz (%s): %s", filepath.Base(y), c.Hata)
		}
		if _, err := os.Stat(y); err == nil {
			t.Fatalf("dosya silinmedi: %s", filepath.Base(y))
		}
	}
	// Surucu koku silinmez (test klasoru ise kullanicinin kendi klasoru, silinmez).
	kok := filepath.VolumeName(klasor) + string(filepath.Separator)
	if c := sil(veriIslem{Yol: kok}); c.Tamam {
		t.Fatal("surucu koku silindi")
	}
}

func b64Test(s string) string { return base64.StdEncoding.EncodeToString([]byte(s)) }

func okuTest(t *testing.T, yol string) string {
	t.Helper()
	c := oku(veriIslem{Yol: yol, Ofset: 0, Uzunluk: maksParcaBoyutu})
	if !c.Tamam {
		t.Fatalf("okuma basarisiz: %s", c.Hata)
	}
	bayt, _ := base64.StdEncoding.DecodeString(c.Veri.(map[string]any)["icerik"].(string))
	return string(bayt)
}
