// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var (
	portFlag    = flag.String("port", "", "port to serve on")
	verboseFlag = flag.Bool("verbose", false, "enable verbose logging")
	staticFlag  = flag.String("static", "", "static files directory")
	binFlag     = flag.String("bin", "", "binary search paths, "+pathHelp)
	fidlFlag    = flag.String("fidl", "", "FIDL library search paths, "+pathHelp)

	pathHelp = fmt.Sprintf(`separated by "%s"`, string(filepath.ListSeparator))
)

func printUsage() {
	program := filepath.Base(os.Args[0])
	message :=
		`Usage: ` + program + ` [flags]

Web server for fidlbolt, a tool for exploring FIDL code and bytes

Flags:
`

	fmt.Fprint(flag.CommandLine.Output(), message)
	flag.PrintDefaults()
}

func main() {
	flag.Usage = printUsage
	flag.Parse()

	static := *staticFlag
	bin := filepath.SplitList(*binFlag)
	fidl := filepath.SplitList(*fidlFlag)
	if static == "" || len(bin) == 0 || len(fidl) == 0 {
		fuchsia := getFuchsiaDir()
		if static == "" {
			static = filepath.Join(filepath.Dir(fuchsia), "fidlbolt", "frontend", "dist")
		}
		if len(bin) == 0 {
			build := getBuildDir(fuchsia)
			bin = []string{
				filepath.Join(build, "host_x64"),
				filepath.Join(build+".zircon", "tools"),
			}
		}
		if len(fidl) == 0 {
			fidl = []string{
				filepath.Join(fuchsia, "sdk", "fidl"),
				filepath.Join(fuchsia, "zircon", "system", "fidl"),
			}
		}
	}
	checkDirs(static)
	checkDirs(bin...)
	checkDirs(fidl...)

	server, err := NewServer(bin, fidl)
	if err != nil {
		log.Fatal(err)
	}

	mux := http.NewServeMux()
	mux.Handle("/", http.FileServer(http.Dir(static)))
	mux.Handle("/convert", &postHandler{server, *verboseFlag})

	timeout := 10 * time.Second
	handler := http.TimeoutHandler(
		mux, timeout, fmt.Sprintf("Request exceeded the %v time limit", timeout))
	handler = logging(handler)

	port := *portFlag
	if port == "" {
		port = os.Getenv("PORT")
		if port == "" {
			port = "8080"
		}
	}

	s := &http.Server{
		Addr:         ":" + port,
		Handler:      handler,
		ReadTimeout:  10 * time.Second,
		WriteTimeout: timeout + 5*time.Second,
	}
	log.Printf("Listening on %s", s.Addr)
	log.Fatal(s.ListenAndServe())
}

type postHandler struct {
	server  *Server
	verbose bool
}

func (h *postHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeError(w, http.StatusMethodNotAllowed, nil)
		return
	}
	if r.Body == nil {
		writeError(w, http.StatusBadRequest, nil)
		return
	}
	var request Request
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}
	if h.verbose {
		log.Printf("Request body: %#v", request)
	}
	if err := request.Validate(); err != nil {
		writeError(w, http.StatusUnprocessableEntity, err)
		return
	}
	response, err := h.server.Serve(r.Context(), &request)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}
	body, err := json.Marshal(response)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(body)
}

func getFuchsiaDir() string {
	dir, ok := os.LookupEnv("FUCHSIA_DIR")
	if !ok {
		log.Fatal("Must set FUCHSIA_DIR or provide all flags")
	}
	return dir
}

func getBuildDir(fuchsia string) string {
	b, err := ioutil.ReadFile(filepath.Join(fuchsia, ".fx-build-dir"))
	if err != nil {
		log.Fatal(err)
	}
	return filepath.Join(fuchsia, strings.TrimSpace(string(b)))
}

func checkDirs(dirs ...string) {
	for _, dir := range dirs {
		if _, err := os.Stat(dir); os.IsNotExist(err) {
			log.Fatalf("%s: directory does not exist", dir)
		}
	}
}

type statusWriter struct {
	http.ResponseWriter
	status int
}

func (sw *statusWriter) WriteHeader(status int) {
	sw.status = status
	sw.ResponseWriter.WriteHeader(status)
}

func logging(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("[%s] %s %s", r.RemoteAddr, r.Method, r.URL)
		sw := statusWriter{ResponseWriter: w}
		handler.ServeHTTP(&sw, r)
		log.Printf("[%s] -> %d %s", r.RemoteAddr, sw.status, http.StatusText(sw.status))
	})
}

func writeError(w http.ResponseWriter, code int, err error) {
	text := fmt.Sprintf("%d %s", code, http.StatusText(code))
	http.Error(w, text, code)
	if err != nil {
		log.Printf("ERROR: %s", err.Error())
	}
}
