package main

import (
	"embed"
	"flag"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"time"

	"kumoly.io/tools/configui/configui"
	"kumoly.io/tools/configui/public"
)

//go:embed templates
var tmplFS embed.FS
var tmpl *template.Template

var (
	flagPath       string
	flagAction     string
	flagAlias      string
	flagConfigPath string

	flagBind    string
	flagLogFile string
	flagAllow   string
	flagVer     bool
)

var Version = "0.0.0"
var Build = "alpha"
var files = map[string]*configui.File{}

func init() {
	// log.SetFlags(0)

	flag.StringVar(&flagConfigPath, "f", "", "path to config file")
	flag.StringVar(&flagPath, "p", "", "path to file, precedence over config")
	flag.StringVar(&flagAlias, "n", "", "alias of file")
	flag.StringVar(&flagAction, "c", "", "cmd to apply")
	flag.StringVar(&flagLogFile, "log", "", "log to file")
	flag.StringVar(&flagAllow, "allow", "", "IPs to allow, blank to allow all")
	flag.StringVar(&flagBind, "bind", "localhost:8000", "address to bind")
	flag.BoolVar(&flagVer, "v", false, "show version")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: configui [options]\n")
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()

	if flagVer {
		fmt.Printf("%v - %v\n", Version, Build)
	}

	// setup logging
	if flagLogFile != "" {
		f, err := os.OpenFile(flagLogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("Error opening file: %v", err)
		}
		defer f.Close()
		mwriter := io.MultiWriter(f, os.Stderr)
		log.SetOutput(mwriter)
	}

	// setup values
	if flagPath != "" {
		if flagAlias == "" {
			flagAlias = flagPath
		}
		files[flagAlias] = &configui.File{
			Path:   flagPath,
			Alias:  flagAlias,
			Action: flagAction,
		}
	} else if flagConfigPath == "" {
		log.Println("no config found")
	} else {
		conf, err := os.ReadFile(flagConfigPath)
		if err != nil {
			log.Fatalln(err)
		}
		ftmp, err := configui.ReadConfig(string(conf))
		if err != nil {
			log.Fatalln(err)
		}
		files = configui.GetFileMap(ftmp)
	}

	// setup routes
	mux := http.NewServeMux()
	mux.HandleFunc("/api/conf", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			getConfigHandler(w, r)
		} else if r.Method == "POST" {
			LoadConfig(w, r)
		} else {
			w.WriteHeader(404)
		}
	})
	mux.HandleFunc("/api/files", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			ListFiles(w, r)
		} else {
			w.WriteHeader(404)
		}
	})
	mux.HandleFunc("/api/file", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			GetFile(w, r)
		} else if r.Method == "POST" {
			PostFile(w, r)
		} else {
			w.WriteHeader(404)
		}
	})
	mux.HandleFunc("/api/apply", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			Apply(w, r)
		} else {
			w.WriteHeader(404)
		}
	})
	mux.HandleFunc("/api/export", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			Download(w, r)
		} else {
			w.WriteHeader(404)
		}
	})

	mux.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.FS(public.FS))))
	tmpl = template.Must(template.New("").ParseFS(tmplFS, "templates/*.tmpl", "templates/**/*.tmpl"))
	setRoutes(mux)
	server := &http.Server{
		Addr:         flagBind,
		WriteTimeout: time.Second * 3,
		ReadTimeout:  time.Second * 30,
		Handler:      Middleware(mux),
	}

	// start server
	log.Println("Listening on", flagBind)
	log.Fatal(server.ListenAndServe())
}
