package main

import (
	"flag"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"

	"srs.epita.fr/fic-server/libfic"
	"srs.epita.fr/fic-server/qa/api"
	"srs.epita.fr/fic-server/settings"
)

type ResponseWriterPrefix struct {
	real   http.ResponseWriter
	prefix string
}

func (r ResponseWriterPrefix) Header() http.Header {
	return r.real.Header()
}

func (r ResponseWriterPrefix) WriteHeader(s int) {
	if v, exists := r.real.Header()["Location"]; exists {
		r.real.Header().Set("Location", r.prefix+v[0])
	}
	r.real.WriteHeader(s)
}

func (r ResponseWriterPrefix) Write(z []byte) (int, error) {
	return r.real.Write(z)
}

func StripPrefix(prefix string, h http.Handler) http.Handler {
	if prefix == "" {
		return h
	}
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if prefix != "/" && r.URL.Path == "/" {
			http.Redirect(w, r, prefix+"/", http.StatusFound)
		} else if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {
			r2 := new(http.Request)
			*r2 = *r
			r2.URL = new(url.URL)
			*r2.URL = *r.URL
			r2.URL.Path = p
			h.ServeHTTP(ResponseWriterPrefix{w, prefix}, r2)
		} else {
			h.ServeHTTP(w, r)
		}
	})
}

func reloadSettings(config *settings.Settings) {
	api.ManagerUsers = config.DelegatedQA
}

func main() {
	// Read paremeters from environment
	if v, exists := os.LookupEnv("FIC_BASEURL"); exists {
		BaseURL = v
	}

	// Read parameters from command line
	var bind = flag.String("bind", "127.0.0.1:8083", "Bind port/socket")
	var dsn = flag.String("dsn", fic.DSNGenerator(), "DSN to connect to the MySQL server")
	flag.StringVar(&BaseURL, "baseurl", BaseURL, "URL prepended to each URL")
	flag.StringVar(&DevProxy, "dev", DevProxy, "Proxify traffic to this host for static assets")
	flag.StringVar(&settings.SettingsDir, "settings", "./SETTINGSDIST", "Base directory where load and save settings")
	flag.StringVar(&api.TeamsDir, "teams", "./TEAMS", "Base directory where save teams JSON files")
	flag.StringVar(&api.Simulator, "simulator", "", "Auth string to simulate (for development only)")
	flag.Parse()

	log.SetPrefix("[qa] ")

	// Sanitize options
	var err error
	log.Println("Checking paths...")
	if BaseURL != "/" {
		BaseURL = path.Clean(BaseURL)
	} else {
		BaseURL = ""
	}
	if api.Simulator != "" {
		if _, err := os.Stat(path.Join(api.TeamsDir, api.Simulator)); os.IsNotExist(err) {
			log.Fatal(err)
		}
	}

	// Load configuration
	settings.LoadAndWatchSettings(path.Join(settings.SettingsDir, settings.SettingsFile), reloadSettings)

	// Database connection
	log.Println("Opening database...")
	if err = fic.DBInit(*dsn); err != nil {
		log.Fatal("Cannot open the database: ", err)
	}
	defer fic.DBClose()

	a := NewApp(BaseURL)
	go a.Start(*bind)

	// Prepare graceful shutdown
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)

	// Wait shutdown signal
	<-interrupt

	log.Print("The service is shutting down...")
	a.Stop()
	log.Println("done")
}
