package main

import (
	"log"
	"net"
	"net/http"
	"strings"

	"github.com/emicklei/go-restful"
	"novit.nc/direktil/local-server/pkg/mime"
	"novit.nc/direktil/pkg/localconfig"
)

func buildWS() *restful.WebService {
	ws := &restful.WebService{}

	// configs API
	ws.Route(ws.POST("/configs").Filter(adminAuth).To(wsUploadConfig).
		Doc("Upload a new current configuration, archiving the previous one"))

	// clusters API
	ws.Route(ws.GET("/clusters").Filter(adminAuth).To(wsListClusters).
		Doc("List clusters"))
	ws.Route(ws.GET("/clusters/{cluster-name}").Filter(adminAuth).To(wsCluster).
		Doc("Get cluster details"))
	ws.Route(ws.GET("/clusters/{cluster-name}/addons").Filter(adminAuth).To(wsClusterAddons).
		Produces(mime.YAML).
		Doc("Get cluster addons").
		Returns(http.StatusOK, "OK", nil).
		Returns(http.StatusNotFound, "The cluster does not exists or does not have addons defined", nil))

	// hosts API
	ws.Route(ws.GET("/hosts").Filter(hostsAuth).To(wsListHosts).
		Doc("List hosts"))

	(&wsHost{
		prefix:  "",
		getHost: detectHost,
	}).register(ws, func(rb *restful.RouteBuilder) {
		rb.Notes("In this case, the host is detected from the remote IP")
	})

	(&wsHost{
		prefix: "/hosts/{host-name}",
		getHost: func(req *restful.Request) string {
			return req.PathParameter("host-name")
		},
	}).register(ws, func(rb *restful.RouteBuilder) {
		rb.Filter(adminAuth)
	})

	return ws
}

func detectHost(req *restful.Request) string {
	r := req.Request
	remoteAddr := r.RemoteAddr

	if *trustXFF {
		if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
			remoteAddr = strings.Split(xff, ",")[0]
		}
	}

	hostIP, _, err := net.SplitHostPort(remoteAddr)

	if err != nil {
		hostIP = remoteAddr
	}

	cfg, err := readConfig()
	if err != nil {
		return ""
	}

	host := cfg.HostByIP(hostIP)

	if host == nil {
		log.Print("no host found for IP ", hostIP)
		return ""
	}

	return host.Name
}

func wsReadConfig(resp *restful.Response) *localconfig.Config {
	cfg, err := readConfig()
	if err != nil {
		log.Print("failed to read config: ", err)
		resp.WriteErrorString(http.StatusServiceUnavailable, "failed to read config")
		return nil
	}

	return cfg
}

func wsNotFound(req *restful.Request, resp *restful.Response) {
	http.NotFound(resp.ResponseWriter, req.Request)
}

func wsError(resp *restful.Response, err error) {
	log.Print("request failed: ", err)
	resp.WriteErrorString(
		http.StatusInternalServerError,
		http.StatusText(http.StatusInternalServerError))
}
