package main

import (
	"embed"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/urfave/cli/v2"
)

//go:generate yarn
//go:generate yarn build
//go:embed dist/*
var embedFs embed.FS

type FileSystem struct {
	efs http.FileSystem
}

func NewFS() *FileSystem {
	return &FileSystem{http.FS(embedFs)}
}

func (fs FileSystem) Open(name string) (http.File, error) {
	f, err := fs.efs.Open(filepath.Join("dist", name))
	if os.IsNotExist(err) {
		return fs.efs.Open("dist/index.html")
	}

	return f, err
}

func main() {
	app := &cli.App{
		Name:  "seenvoy",
		Usage: "see the configs of the Envoy",
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:  "addr",
				Value: ":8080",
				Usage: "specify the seenvoy listen address",
			},
			&cli.StringFlag{
				Name:     "target",
				Usage:    "specify the admin URL of the envoy",
				Aliases:  []string{"t"},
				Required: true,
			},
		},
		Action: func(c *cli.Context) error {
			reverseProxy, err := buildReverseProxy(c.String("target"))
			if err != nil {
				return err
			}

			http.NewServeMux()
			http.Handle("/", http.FileServer(NewFS()))
			http.Handle("/api/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				r.URL.Path = r.URL.Path[len("/api/"):]
				reverseProxy.ServeHTTP(w, r)
			}))

			log.Println("seenvoy listening on", c.String("addr"))
			return http.ListenAndServe(c.String("addr"), nil)
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}

}

func buildReverseProxy(s string) (*httputil.ReverseProxy, error) {
	if !strings.Contains(s, "://") {
		s = "http://" + s
	}

	target, err := url.Parse(s)
	if err != nil {
		return nil, err
	}

	log.Println("reverse proxy target:", target)
	return httputil.NewSingleHostReverseProxy(target), nil
}