package webConfig

import (
	"fmt"
	"git.ssns.se/git/frozendragon/pokemon-go-trade/internal/configKey"
	"git.ssns.se/git/frozendragon/pokemon-go-trade/internal/db"
	"git.ssns.se/git/frozendragon/pokemon-go-trade/internal/pokemon"
	"git.ssns.se/git/frozendragon/pokemon-go-trade/internal/web"
	nested "github.com/antonfisher/nested-logrus-formatter"
	"github.com/go-chi/chi"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func CreateServer() {
	log := SetupLogging()
	log.Info("Starting application")

	config, err := setupEnvironment()
	if err != nil {
		panic(err)
	}

	database, err := sqlx.Connect("postgres", fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", config.GetString(configKey.DatabaseUser), config.GetString(configKey.DatabasePassword), config.GetString(configKey.DatabaseUser)))
	if err != nil {
		panic(err)
	}

	dbPackage := &db.Package{
		Db: database,
	}

	pokemonPackage := &pokemon.Package{
		Db: dbPackage,
	}

	webPackage := web.WebPackage{
		Config:  config,
		Log:     log,
		Pokemon: pokemonPackage,
	}

	r := chi.NewRouter()
	workDir, _ := os.Getwd()
	filesDir := filepath.Join(workDir, "static/html/build")
	filesImagesDir := filepath.Join(workDir, "static/images")

	r.Route("/", func(r chi.Router) {
		FileServer(r, "/", http.Dir(filesDir))
	})
	r.Route("/api", func(r chi.Router) {
		r.Get("/available-pokemon", webPackage.GetAvailablePokemon)
		r.Get("/stored-pokemon-have", webPackage.GetStoredPokemonHave)
		r.Get("/stored-pokemon-want", webPackage.GetStoredPokemonWant)
		r.Post("/stored-pokemon-want", webPackage.CreateStoredPokemonWant)
		r.Delete("/stored-pokemon-want", webPackage.DeleteStoredPokemonWant)
		r.Post("/stored-pokemon", webPackage.PostStoredPokemon)
		r.Get("/linked-stored-pokemon", webPackage.GetLinkedStoredPokemon)
		r.Post("/linked-stored-pokemon", webPackage.PostLinkedStoredPokemon)
	})

	FileServer(r, "/image", http.Dir(filesImagesDir))

	err = http.ListenAndServe(":8080", r)
	if err != nil {
		panic(err)
	}
}

func setupEnvironment() (*viper.Viper, error) {
	var config = viper.New()
	config.SetConfigType("json")
	file, err := os.Open("config/environment.json")
	if err != nil {
		return nil, err
	}
	err = config.ReadConfig(file)
	if err != nil {
		return nil, err
	}
	config.SetConfigType("json")
	file, err = os.Open(fmt.Sprintf("config/%s.json", config.GetString("environment")))
	if err != nil {
		return nil, err
	}
	err = config.ReadConfig(file)
	if err != nil {
		return nil, err
	}
	return config, nil
}

func SetupLogging() *logrus.Logger {
	log := logrus.New()
	log.SetFormatter(&nested.Formatter{
		HideKeys:    true,
		FieldsOrder: []string{"component", "category"},
	})
	file, err := os.OpenFile("log/info.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	mw := io.MultiWriter(os.Stdout, file)
	if err == nil {
		log.SetOutput(mw)
	} else {
		log.Info("Failed to log to file, using default stderr")
	}
	log.SetLevel(logrus.InfoLevel)
	return log
}

func FileServer(r chi.Router, path string, root http.FileSystem) {
	if strings.ContainsAny(path, "{}*") {
		panic("FileServer does not permit URL parameters.")
	}

	fs := http.StripPrefix(path, http.FileServer(root))

	if path != "/" && path[len(path)-1] != '/' {
		r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
		path += "/"
	}
	path += "*"

	r.Get(path, func(w http.ResponseWriter, r *http.Request) {
		fs.ServeHTTP(w, r)
	})
}
