package main

// USB (çıkarılabilir sürücü) işlemleri. Yalnızca Windows'ta derlenir.

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
	"unsafe"
)

var (
	kernel32         = syscall.NewLazyDLL("kernel32.dll")
	procGetDriveType = kernel32.NewProc("GetDriveTypeW")
)

const driveRemovable = 2

var surucuRegex = regexp.MustCompile(`^[A-Za-z]:$`)

func cikarilabilirMi(surucu string) bool {
	p, err := syscall.UTF16PtrFromString(surucu + `\`)
	if err != nil {
		return false
	}
	t, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(p)))
	return t == driveRemovable
}

func cikarilabilirSurucular() []string {
	var liste []string
	for harf := 'A'; harf <= 'Z'; harf++ {
		s := fmt.Sprintf("%c:", harf)
		if _, err := os.Stat(s + `\`); err == nil && cikarilabilirMi(s) {
			liste = append(liste, s)
		}
	}
	return liste
}

// usbSurucuGecerli: yalnızca takılı çıkarılabilir sürücülere izin verilir.
func usbSurucuGecerli(surucu string) bool {
	return surucuRegex.MatchString(surucu) && cikarilabilirMi(surucu)
}

func jsonYaz(w http.ResponseWriter, deger interface{}) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("Cache-Control", "no-store")
	json.NewEncoder(w).Encode(deger)
}

// usbIslemi: /usb ve alt yolları. Döner: işlendiyse true.
func usbIslemi(w http.ResponseWriter, r *http.Request) bool {
	switch {
	case r.URL.Path == "/usb" && r.Method == http.MethodGet:
		jsonYaz(w, cikarilabilirSurucular())
		return true

	case r.URL.Path == "/usb/nc" && r.Method == http.MethodGet:
		surucu := r.URL.Query().Get("surucu")
		if !usbSurucuGecerli(surucu) {
			http.Error(w, "geçersiz sürücü", http.StatusForbidden)
			return true
		}
		girdiler, err := os.ReadDir(surucu + `\`)
		if err != nil {
			http.Error(w, "sürücü okunamadı", http.StatusInternalServerError)
			return true
		}
		type dosya struct {
			Name string `json:"name"`
			Size int64  `json:"size"`
		}
		sonuc := []dosya{}
		for _, g := range girdiler {
			if g.IsDir() || !strings.EqualFold(filepath.Ext(g.Name()), ".nc") {
				continue
			}
			bilgi, err := g.Info()
			if err != nil {
				continue
			}
			sonuc = append(sonuc, dosya{Name: g.Name(), Size: bilgi.Size()})
		}
		jsonYaz(w, sonuc)
		return true

	case r.URL.Path == "/usb/yaz" && r.Method == http.MethodPost:
		surucu := r.URL.Query().Get("surucu")
		if !usbSurucuGecerli(surucu) {
			http.Error(w, "geçersiz sürücü", http.StatusForbidden)
			return true
		}
		ad := filepath.Base(r.URL.Query().Get("ad"))
		if ad == "." || ad == "/" || ad == `\` || ad == "" {
			http.Error(w, "geçersiz dosya adı", http.StatusBadRequest)
			return true
		}
		if !strings.EqualFold(filepath.Ext(ad), ".nc") {
			ad += ".NC"
		}
		hedef := filepath.Join(surucu+`\`, ad)
		if _, err := os.Stat(hedef); err == nil && r.URL.Query().Get("uzerineYaz") != "1" {
			taban := strings.TrimSuffix(ad, filepath.Ext(ad))
			for i := 1; ; i++ {
				aday := filepath.Join(surucu+`\`, fmt.Sprintf("%s_%d.NC", taban, i))
				if _, err := os.Stat(aday); err != nil {
					hedef = aday
					break
				}
			}
		}
		dosya, err := os.Create(hedef)
		if err != nil {
			http.Error(w, "dosya yazılamadı", http.StatusInternalServerError)
			return true
		}
		_, err = io.Copy(dosya, r.Body)
		kapatHata := dosya.Close()
		if err != nil || kapatHata != nil {
			os.Remove(hedef)
			http.Error(w, "yazma hatası", http.StatusInternalServerError)
			return true
		}
		jsonYaz(w, map[string]string{"dosya": filepath.Base(hedef)})
		return true

	case r.URL.Path == "/usb/sil" && r.Method == http.MethodPost:
		var istek struct {
			Surucu   string   `json:"surucu"`
			Dosyalar []string `json:"dosyalar"`
		}
		if err := json.NewDecoder(r.Body).Decode(&istek); err != nil {
			http.Error(w, "geçersiz istek", http.StatusBadRequest)
			return true
		}
		if !usbSurucuGecerli(istek.Surucu) {
			http.Error(w, "geçersiz sürücü", http.StatusForbidden)
			return true
		}
		type sonuc struct {
			Name  string `json:"name"`
			Ok    bool   `json:"ok"`
			Hata  string `json:"hata,omitempty"`
		}
		cikti := []sonuc{}
		for _, ad := range istek.Dosyalar {
			// Yalnızca kök dizindeki .nc dosyaları; yol bileşeni kabul edilmez.
			if filepath.Base(ad) != ad || !strings.EqualFold(filepath.Ext(ad), ".nc") {
				cikti = append(cikti, sonuc{Name: ad, Ok: false, Hata: "izinli değil"})
				continue
			}
			if err := os.Remove(filepath.Join(istek.Surucu+`\`, ad)); err != nil {
				cikti = append(cikti, sonuc{Name: ad, Ok: false, Hata: err.Error()})
				continue
			}
			cikti = append(cikti, sonuc{Name: ad, Ok: true})
		}
		jsonYaz(w, cikti)
		return true
	}
	return false
}
