// main.go
package main

import (
	"bufio"
	"embed"
	"encoding/json"
	"fmt"
	"io"
	"io/fs"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"

	webview "github.com/webview/webview_go"
)

//go:embed index.html ui/* images/*
var content embed.FS

type saveReq struct {
	Filename string `json:"filename"`
	Content  string `json:"content"`
}

type saveResp struct {
	Path string `json:"path"`
}

func main() {
	// Static files
	subFS, err := fs.Sub(content, ".")
	if err != nil {
		log.Fatalf("fs.Sub error: %v", err)
	}
	mux := http.NewServeMux()
	mux.Handle("/", http.FileServer(http.FS(subFS)))

	// /save endpoint writes to Downloads
	mux.HandleFunc("/save", func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		defer func() { log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start)) }()

		if r.Method != http.MethodPost {
			http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
			return
		}
		var req saveReq
		if err := json.NewDecoder(io.LimitReader(r.Body, 10<<20)).Decode(&req); err != nil {
			http.Error(w, "bad json", http.StatusBadRequest)
			return
		}
		if req.Filename == "" {
			req.Filename = fmt.Sprintf("relibre-%d.html", time.Now().Unix())
		}
		req.Filename = sanitizeFilename(req.Filename)

		dir := downloadsDir()
		if err := os.MkdirAll(dir, 0o755); err != nil {
			http.Error(w, "mkdir failed", http.StatusInternalServerError)
			return
		}
		path := filepath.Join(dir, req.Filename)
		if err := os.WriteFile(path, []byte(req.Content), 0o644); err != nil {
			http.Error(w, "write failed", http.StatusInternalServerError)
			return
		}
		log.Printf("Saved HTML -> %s", path)

		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(saveResp{Path: path})
	})

	// Simple request logger
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		mux.ServeHTTP(w, r)
		log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start))
	})

	// Start server on ephemeral port
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		log.Fatalf("listen: %v", err)
	}
	addr := ln.Addr().String()
	srv := &http.Server{Handler: handler, ReadHeaderTimeout: 5 * time.Second}

	go func() {
		log.Printf("HTTP listening on http://%s", addr)
		if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed {
			log.Fatalf("http serve: %v", err)
		}
	}()

	// Native webview window (debug true for dev tools/log signals)
	debug := true
	w := webview.New(debug)
	defer w.Destroy()
	w.SetTitle("Relibre")
	w.SetSize(1100, 750, webview.HintNone)
	w.Navigate(fmt.Sprintf("http://%s", addr))
	w.Run()

	_ = srv.Close()
	if runtime.GOOS == "linux" {
		time.Sleep(100 * time.Millisecond)
	}
}

func sanitizeFilename(name string) string {
	name = strings.TrimSpace(name)
	if name == "" {
		return "relibre.html"
	}
	if !strings.HasSuffix(strings.ToLower(name), ".html") {
		name += ".html"
	}
	re := regexp.MustCompile(`[<>:"/\\|?*\x00-\x1F]`)
	return re.ReplaceAllString(name, "_")
}

func downloadsDir() string {
	if p := readXDGDownloads(); p != "" {
		return p
	}
	home, _ := os.UserHomeDir()
	if home == "" {
		return "./"
	}
	return filepath.Join(home, "Downloads")
}

func readXDGDownloads() string {
	home, _ := os.UserHomeDir()
	if home == "" {
		return ""
	}
	path := filepath.Join(home, ".config", "user-dirs.dirs")
	f, err := os.Open(path)
	if err != nil {
		return ""
	}
	defer f.Close()
	sc := bufio.NewScanner(f)
	for sc.Scan() {
		line := sc.Text()
		if strings.HasPrefix(line, "XDG_DOWNLOAD_DIR=") {
			raw := strings.TrimPrefix(line, "XDG_DOWNLOAD_DIR=")
			raw = strings.Trim(raw, `"`)
			raw = strings.ReplaceAll(raw, "$HOME", home)
			return raw
		}
	}
	return ""
}

