package start

import (
	"fmt"
	"net"
	"net/http"
	"os"

	"github.com/apex/log"
	"github.com/pkg/browser"
	"github.com/pkg/errors"
	"github.com/tj/kingpin"

	"github.com/apex/up/handler"
	"github.com/apex/up/internal/cli/root"
	"github.com/apex/up/internal/logs/text"
	"github.com/apex/up/internal/stats"
)

func init() {
	cmd := root.Command("start", "Start development server.")
	cmd.Example(`up start`, "Start development server on port 3000.")
	cmd.Example(`up start -o`, "Start development server and open in the browser.")
	cmd.Example(`up start --address :5000`, "Start development server on port 5000.")
	cmd.Example(`up start -c 'go run main.go'`, "Override proxy command.")
	cmd.Example(`up start -oc 'gin --port $PORT'`, "Override proxy command and open in the browser.")

	stage := cmd.Flag("stage", "Target stage name.").Short('s').Default("development").String()
	command := cmd.Flag("command", "Proxy command override").Short('c').String()
	open := cmd.Flag("open", "Open endpoint in the browser.").Short('o').Bool()
	addr := cmd.Flag("address", "Address for server.").Default("localhost:3000").String()

	cmd.Action(func(_ *kingpin.ParseContext) error {
		log.SetHandler(text.New(os.Stdout))

		c, p, err := root.Init()
		if err != nil {
			return errors.Wrap(err, "initializing")
		}

		for k, v := range c.Environment {
			os.Setenv(k, v)
		}

		stats.Track("Start", map[string]interface{}{
			"address":     *addr,
			"has_command": *command != "",
		})

		if err := p.Init(*stage); err != nil {
			return errors.Wrap(err, "initializing")
		}

		if err := c.Override(*stage); err != nil {
			return errors.Wrap(err, "overriding")
		}

		if s := *command; s != "" {
			c.Proxy.Command = s
		}

		h, err := handler.FromConfig(c)
		if err != nil {
			return errors.Wrap(err, "selecting handler")
		}

		h, err = handler.New(c, h)
		if err != nil {
			return errors.Wrap(err, "initializing handler")
		}

		if *open {
			_, port, _ := net.SplitHostPort(*addr)
			browser.OpenURL(fmt.Sprintf("http://localhost:%s", port))
		}

		log.WithField("address", "http://"+*addr).Info("listening")
		if err := http.ListenAndServe(*addr, h); err != nil {
			return errors.Wrap(err, "binding")
		}

		return nil
	})
}
