package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/mathieu/project-notes/internal/api"
	"github.com/mathieu/project-notes/internal/indexer"
	"github.com/mathieu/project-notes/internal/watcher"
)

func main() {
	addr := flag.String("addr", ":8080", "Adresse d ecoute HTTP")
	notesDir := flag.String("notes-dir", "./notes", "Repertoire contenant les notes Markdown")
	flag.Parse()

	logger := log.New(os.Stdout, "[server] ", log.LstdFlags)

	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()

	if err := ensureDir(*notesDir); err != nil {
		logger.Fatalf("repertoire notes invalide: %v", err)
	}

	idx := indexer.New()
	if err := idx.Load(*notesDir); err != nil {
		logger.Fatalf("echec de l indexation initiale: %v", err)
	}

	w, err := watcher.Start(ctx, *notesDir, idx, logger)
	if err != nil {
		logger.Fatalf("echec du watcher: %v", err)
	}
	defer w.Close()

	// Pre-parse templates
	templates, err := template.ParseGlob("templates/*.html")
	if err != nil {
		logger.Fatalf("echec de l analyse des templates: %v", err)
	}

	mux := http.NewServeMux()

	// Servir les fichiers statiques
	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" {
			http.NotFound(w, r)
			return
		}
		if err := templates.ExecuteTemplate(w, "index.html", nil); err != nil {
			logger.Printf("erreur d execution du template index: %v", err)
			http.Error(w, "erreur interne", http.StatusInternalServerError)
		}
	})

	apiHandler := api.NewHandler(*notesDir, idx, templates, logger)
	mux.Handle("/api/search", apiHandler)
	mux.Handle("/api/folders/create", apiHandler)
	mux.Handle("/api/files/move", apiHandler)
	mux.Handle("/api/home", apiHandler)
	mux.Handle("/api/notes/", apiHandler)
	mux.Handle("/api/tree", apiHandler)

	srv := &http.Server{
		Addr:         *addr,
		Handler:      mux,
		ReadTimeout:  15 * time.Second,
		WriteTimeout: 15 * time.Second,
		IdleTimeout:  60 * time.Second,
	}

	logger.Printf("demarrage du serveur sur %s", *addr)

	go func() {
		<-ctx.Done()
		shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		if err := srv.Shutdown(shutdownCtx); err != nil {
			logger.Printf("erreur durant l arret du serveur: %v", err)
		}
	}()

	if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
		logger.Fatalf("arret inattendu du serveur: %v", err)
	}
}

func ensureDir(path string) error {
	info, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("le chemin %s n existe pas", path)
		}
		return err
	}
	if !info.IsDir() {
		return fmt.Errorf("%s n est pas un repertoire", path)
	}
	return nil
}
