package api

import (
	"context"
	"net/http"
	"time"

	"github.com/gorilla/mux"
	"github.com/unrolled/render"
	"github.com/urfave/negroni"
)

// APIPrefix is api prefix
const APIPrefix = "/agent"

// Agent is the agent to let the controller to control the docker.
type Agent struct {
	addr string
	s    *http.Server
}

// NewAgent creates the node with given address
func NewAgent(addr string) *Agent {
	n := &Agent{
		addr: addr,
	}

	return n
}

// Run runs the Node API server
func (a *Agent) Run() error {
	a.s = &http.Server{
		Addr:    a.addr,
		Handler: a.createHandler(),
	}
	return a.s.ListenAndServe()
}

// Close closes the Node.
func (a *Agent) Close() {
	if a.s != nil {
		ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
		a.s.Shutdown(ctx)
		cancel()
	}
}

func (a *Agent) createHandler() http.Handler {
	engine := negroni.New()
	recover := negroni.NewRecovery()
	engine.Use(recover)

	router := mux.NewRouter()
	subRouter := a.createRouter()
	router.PathPrefix(APIPrefix).Handler(
		negroni.New(negroni.Wrap(subRouter)),
	)

	engine.UseHandler(router)
	return engine
}

func (a *Agent) createRouter() *mux.Router {
	rd := render.New(render.Options{
		IndentJSON: true,
	})

	router := mux.NewRouter().PathPrefix(APIPrefix).Subrouter()

	processHandler := newProcessHandler(a, rd)
	router.HandleFunc("/process/{name}/start", processHandler.Start).Methods("POST")
	router.HandleFunc("/process/{name}/stop", processHandler.Stop).Methods("POST")
	router.HandleFunc("/process/{name}/kill/{signal}", processHandler.Kill).Methods("POST")
	router.HandleFunc("/process/{name}/up", processHandler.Up).Methods("POST")
	router.HandleFunc("/process/{name}/down", processHandler.Down).Methods("POST")
	router.HandleFunc("/process/{name}/state", processHandler.State).Methods("GET")
	router.HandleFunc("/process/{name}/detail", processHandler.Detail).Methods("GET")

	// shell cmd
	router.HandleFunc("/shell", processHandler.Shell).Methods("POST")

	return router
}
