package probe

import (
	"fmt"
	"net"
	"reflect"

	"git.loafle.net/commons/logging-go"
	"git.loafle.net/commons/server-go"
	csgw "git.loafle.net/commons/server-go/socket/web"
	occi "git.loafle.net/overflow/commons-go/core/interfaces"
	"git.loafle.net/overflow/probe/config"
)

type ServerHandler interface {
	csgw.ServerHandler
}

type ServerHandlers struct {
	csgw.ServerHandlers

	Services        []interface{}
	OrderedServices []reflect.Type
}

func (sh *ServerHandlers) Init(serverCtx server.ServerCtx) error {
	if err := sh.ServerHandlers.Init(serverCtx); nil != err {
		return err
	}

	if err := occi.ExecServices(sh.Services, occi.ServiceMethodInit, sh.OrderedServices, false); nil != err {
		return err
	}

	return nil
}

func (sh *ServerHandlers) OnStart(serverCtx server.ServerCtx) error {
	if err := sh.ServerHandlers.OnStart(serverCtx); nil != err {
		return err
	}

	if err := occi.ExecServices(sh.Services, occi.ServiceMethodStart, sh.OrderedServices, false); nil != err {
		return err
	}
	return nil
}

func (sh *ServerHandlers) OnStop(serverCtx server.ServerCtx) {
	if err := occi.ExecServices(sh.Services, occi.ServiceMethodStop, sh.OrderedServices, true); nil != err {
		logging.Logger().Errorf("Service stop err %v", err)
	}

	sh.ServerHandlers.OnStop(serverCtx)
}

func (sh *ServerHandlers) Destroy(serverCtx server.ServerCtx) {
	if err := occi.ExecServices(sh.Services, occi.ServiceMethodDestroy, sh.OrderedServices, true); nil != err {
		logging.Logger().Errorf("Service destroy err %v", err)
	}

	sh.ServerHandlers.Destroy(serverCtx)
}

func (sh *ServerHandlers) Listener(serverCtx server.ServerCtx) (net.Listener, error) {
	for i := 60000; i < 61000; i++ {
		addr := fmt.Sprintf("localhost:%d", i)
		l, err := net.Listen("tcp", addr)
		if nil == err {
			config.ProbePortNumber = int64(i)
			return l, nil
		}
	}

	return nil, fmt.Errorf("Cannot find availrable port")
}

func (sh *ServerHandlers) Validate() error {
	if err := sh.ServerHandlers.Validate(); nil != err {
		return err
	}

	if nil == sh.Services {
		return fmt.Errorf("Services must be specified")
	}

	if nil == sh.OrderedServices {
		return fmt.Errorf("OrderedServices must be specified")
	}

	return nil
}
