package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

var Info = log.New(os.Stdout, "\u001b[34mINFO: \u001B[0m", log.LstdFlags|log.Lshortfile)
var Warning = log.New(os.Stdout, "\u001b[33mWARNING: \u001B[0m", log.LstdFlags|log.Lshortfile)
var Error = log.New(os.Stdout, "\u001b[31mERROR: \u001b[0m", log.LstdFlags|log.Lshortfile)
var Debug = log.New(os.Stdout, "\u001b[36mDEBUG: \u001B[0m", log.LstdFlags|log.Lshortfile)

func upload_file(w http.ResponseWriter, req *http.Request) {
	file, fileHeader, err := req.FormFile("file")
	if err != nil {
		Error.Println(err)
	}
	defer file.Close()

	f, err := os.OpenFile(fmt.Sprintf("%v/%v", get_envvar_or_fatal("SFU_FILES_DIR"), fileHeader.Filename), os.O_WRONLY|os.O_CREATE, 0666)
	defer f.Close()
	io.Copy(f, file)
}

func list_uploaded_files(w http.ResponseWriter, req *http.Request) {
	files_dir := get_envvar_or_fatal("SFU_FILES_DIR")
	Info.Println(fmt.Sprintf("server: will list uploaded files on %v", files_dir))
	files, err := ioutil.ReadDir(files_dir)
	if err != nil {
		Warning.Println(fmt.Sprintf("%v does not exist", files_dir))
		Info.Println(fmt.Sprintf("will create %v", files_dir))
		_ = os.Mkdir(files_dir, os.ModePerm)
	}
	for _, f := range files {
		fmt.Fprintf(w, "%v\n", f.Name())
	}
}

func get_envvar_or_fatal(envvar_name string) string {
	envvar_value, isSet := os.LookupEnv(envvar_name)
	if !isSet {
		Error.Println(fmt.Sprintf("%v is not set", envvar_name))
		os.Exit(1)
	}
	return envvar_value
}

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		path := req.URL.Path
		Info.Println(fmt.Sprintf("received %v on %v", req.Method, path))
		if path != "/" {
			err_msg := fmt.Sprintf("path %v does not exist", path)
			http.Error(w, err_msg, http.StatusNotFound)
			Warning.Println(err_msg)
			Error.Println(fmt.Sprintf("will return %v", http.StatusNotFound))
			return
		}
		switch req.Method {
		case http.MethodGet:
			list_uploaded_files(w, req)
		case http.MethodPost:
			upload_file(w, req)
		default:
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			Warning.Println(fmt.Sprintf("%v not allowed", req.Method))
			Error.Println(fmt.Sprintf("will return %v", http.StatusMethodNotAllowed))
		}
	})
	port := fmt.Sprintf(":%v", get_envvar_or_fatal("SFU_PORT"))
	Info.Println(fmt.Sprintf("running SFU on port %v", port))
	err := http.ListenAndServe(port, nil)
	if err != nil {
		Error.Println(fmt.Sprintf("%v port may not be available", port))
		os.Exit(1)
	}
}
