package admin

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"

	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/schedule"
	"mongo.games.com/goserver/core/utils"
)

// MyAdminApp is the default AdminApp used by admin module.
var MyAdminApp *AdminApp

// AdminIndex is the default http.Handler for admin module.
// it matches url pattern "/".
func AdminIndex(rw http.ResponseWriter, r *http.Request) {
	rw.Write([]byte("Welcome to Admin Dashboard\n"))
	rw.Write([]byte("There are servral functions:\n"))
	rw.Write([]byte(fmt.Sprintf("1. Get runtime profiling data by the pprof, http://%s:%d/prof\n", Config.AdminHttpAddr, Config.AdminHttpPort)))
	rw.Write([]byte(fmt.Sprintf("2. Get healthcheck result from http://%s:%d/healthcheck\n", Config.AdminHttpAddr, Config.AdminHttpPort)))
	rw.Write([]byte(fmt.Sprintf("3. Get current task infomation from task http://%s:%d/task \n", Config.AdminHttpAddr, Config.AdminHttpPort)))
	rw.Write([]byte(fmt.Sprintf("4. To run a task passed a param http://%s:%d/runtask\n", Config.AdminHttpAddr, Config.AdminHttpPort)))
	rw.Write([]byte(fmt.Sprintf("5. Get all confige & router infomation http://%s:%d/listconf\n", Config.AdminHttpAddr, Config.AdminHttpPort)))

}

// ListConf is the http.Handler of displaying all configuration values as key/value pair.
// it's registered with url pattern "/listconf" in admin module.
func ListConf(rw http.ResponseWriter, r *http.Request) {
	rw.Write([]byte("unimpletement"))
}

// ProfIndex is a http.Handler for showing profile command.
// it's in url pattern "/prof" in admin module.
func ProfIndex(rw http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	command := r.Form.Get("command")
	if command != "" {
		utils.ProcessInput(command, rw)
	} else {
		rw.Write([]byte("request url like '/prof?command=lookup goroutine'\n"))
		rw.Write([]byte("the command have below types:\n"))
		rw.Write([]byte("1. lookup goroutine\n"))
		rw.Write([]byte("2. lookup heap\n"))
		rw.Write([]byte("3. lookup threadcreate\n"))
		rw.Write([]byte("4. lookup block\n"))
		rw.Write([]byte("5. start cpuprof\n"))
		rw.Write([]byte("6. stop cpuprof\n"))
		rw.Write([]byte("7. get memprof\n"))
		rw.Write([]byte("8. gc summary\n"))
		rw.Write([]byte("9. logic statistics\n"))
	}
}

// Healthcheck is a http.Handler calling health checking and showing the result.
// it's in "/healthcheck" pattern in admin module.
func Healthcheck(rw http.ResponseWriter, req *http.Request) {
	defer utils.DumpStackIfPanic("Admin Healthcheck")
	for name, h := range utils.AdminCheckList {
		if err := h.Check(); err == nil {
			fmt.Fprintf(rw, "%s : ok\n", name)
		} else {
			fmt.Fprintf(rw, "%s : %s\n", name, err.Error())
		}
	}
}

// TaskStatus is a http.Handler with running task status (task name, status and the last execution).
// it's in "/task" pattern in admin module.
func TaskStatus(rw http.ResponseWriter, req *http.Request) {
	tasks := schedule.GetAllTask()
	for tname, tk := range tasks {
		fmt.Fprintf(rw, "%s:%s:%s", tname, tk.GetStatus(), tk.GetPrev().String())
	}
}

type TaskRunResult struct {
	Code int
	Err  string
}

// RunTask is a http.Handler to run a Task from the "query string.
// the request url likes /runtask?taskname=sendmail.
func RunTask(rw http.ResponseWriter, req *http.Request) {
	defer req.ParseForm()
	taskname := req.Form.Get("taskname")
	trr := &TaskRunResult{}
	t := schedule.GetTask(taskname)
	if t != nil {
		err := t.Run()
		if err != nil {
			trr.Code = 1
			trr.Err = err.Error()
		} else {
			trr.Code = 0
		}
	} else {
		trr.Err = fmt.Sprintf("there's no task which named:%s", taskname)
		trr.Code = 2
	}
	b, _ := json.Marshal(trr)
	fmt.Println(string(b[:]))
	rw.Write(b)
}

// AdminApp is an http.HandlerFunc map used as AdminApp.
type AdminApp struct {
	routers map[string]http.HandlerFunc
}

// Route adds http.HandlerFunc to AdminApp with url pattern.
func (admin *AdminApp) Route(pattern string, f http.HandlerFunc) {
	admin.routers[pattern] = f
}

// Start AdminApp http server.
// Its addr is defined in configuration file as adminhttpaddr and adminhttpport.
func (admin *AdminApp) Start(AdminHttpAddr string, AdminHttpPort int) {
	for p, f := range admin.routers {
		http.Handle(p, f)
	}

	addr := fmt.Sprintf("%s:%d", AdminHttpAddr, AdminHttpPort)
	l, err := net.Listen("tcp", addr)
	if err != nil {
		logger.Logger.Critical("Admin Listen error: ", err)
		return
	}

	logger.Logger.Infof("Admin Serve: %s", l.Addr())

	go func() {
		server := &http.Server{}
		err = server.Serve(l)
		if err != nil {
			logger.Logger.Critical("Admin Serve: ", err)
		}
	}()
}

func init() {
	MyAdminApp = &AdminApp{
		routers: make(map[string]http.HandlerFunc),
	}
	//MyAdminApp.Route("/", AdminIndex)
	//MyAdminApp.Route("/prof", ProfIndex)
	//MyAdminApp.Route("/healthcheck", Healthcheck)
	//MyAdminApp.Route("/task", TaskStatus)
	//MyAdminApp.Route("/runtask", RunTask)
	//MyAdminApp.Route("/listconf", ListConf)
}
