package server

import (
	"net/http"
	"time"

	"git.loafle.net/overflow/overflow_service_websocket/config"
	uuid "github.com/satori/go.uuid"
)

const (
	// DefaultWriteTimeout is default value of Write Timeout
	DefaultWriteTimeout = 0
	// DefaultReadTimeout is default value of Read Timeout
	DefaultReadTimeout = 0
	// DefaultPongTimeout is default value of Pong Timeout
	DefaultPongTimeout = 60 * time.Second
	// DefaultPingTimeout is default value of Ping Timeout
	DefaultPingTimeout = 10 * time.Second
	// DefaultPingPeriod is default value of Ping Period
	DefaultPingPeriod = (DefaultPongTimeout * 9) / 10
	// DefaultMaxMessageSize is default value of Max Message Size
	DefaultMaxMessageSize = 1024
	// DefaultReadBufferSize is default value of Read Buffer Size
	DefaultReadBufferSize = 4096
	// DefaultWriteBufferSize is default value of Write Buffer Size
	DefaultWriteBufferSize = 4096
)

var (
	// DefaultIDGenerator returns the UUID of the client
	DefaultIDGenerator = func(*http.Request) string { return uuid.NewV4().String() }
)

// Options is configuration of the websocket server
type Options struct {
	OnError         func(res http.ResponseWriter, req *http.Request, status int, reason error)
	OnCheckOrigin   func(req *http.Request) bool
	WriteTimeout    time.Duration
	ReadTimeout     time.Duration
	PongTimeout     time.Duration
	PingTimeout     time.Duration
	PingPeriod      time.Duration
	MaxMessageSize  int64
	BinaryMessage   bool
	ReadBufferSize  int
	WriteBufferSize int
	IDGenerator     func(*http.Request) string
}

func NewOptions(c *config.WebsocketConfig) *Options {
	o := &Options{
		WriteTimeout:    time.Duration(c.WriteTimeout) * time.Second,
		ReadTimeout:     time.Duration(c.ReadTimeout) * time.Second,
		PongTimeout:     time.Duration(c.PongTimeout) * time.Second,
		PingTimeout:     time.Duration(c.PingTimeout) * time.Second,
		MaxMessageSize:  c.MaxMessageSize,
		BinaryMessage:   c.UseBinaryMessage,
		ReadBufferSize:  c.ReadBufferSize,
		WriteBufferSize: c.WriteBufferSize,
	}
	o.Validate()
	o.PongTimeout = o.PongTimeout * time.Second
	o.PingTimeout = o.PingTimeout * time.Second
	o.PingPeriod = (o.PingTimeout * 9) / 10
	return o
}

// Set is the func which makes the OptionSet an OptionSetter, this is used mostly
func (o *Options) Set(main *Options) {
	main.OnError = o.OnError
	main.OnCheckOrigin = o.OnCheckOrigin
	main.WriteTimeout = o.WriteTimeout
	main.ReadTimeout = o.ReadTimeout
	main.PongTimeout = o.PongTimeout
	main.PingTimeout = o.PingTimeout
	main.PingPeriod = o.PingPeriod
	main.MaxMessageSize = o.MaxMessageSize
	main.BinaryMessage = o.BinaryMessage
	main.ReadBufferSize = o.ReadBufferSize
	main.WriteBufferSize = o.WriteBufferSize
	main.IDGenerator = o.IDGenerator
}

// Validate validates the configuration
func (o *Options) Validate() {

	if o.WriteTimeout < 0 {
		o.WriteTimeout = DefaultWriteTimeout
	}

	if o.ReadTimeout < 0 {
		o.ReadTimeout = DefaultReadTimeout
	}

	if o.PongTimeout < 0 {
		o.PongTimeout = DefaultPongTimeout
	}

	if o.PingPeriod <= 0 {
		o.PingPeriod = DefaultPingPeriod
	}

	if o.MaxMessageSize <= 0 {
		o.MaxMessageSize = DefaultMaxMessageSize
	}

	if o.ReadBufferSize <= 0 {
		o.ReadBufferSize = DefaultReadBufferSize
	}

	if o.WriteBufferSize <= 0 {
		o.WriteBufferSize = DefaultWriteBufferSize
	}

	if o.OnError == nil {
		o.OnError = func(res http.ResponseWriter, req *http.Request, status int, reason error) {
		}
	}

	if o.OnCheckOrigin == nil {
		o.OnCheckOrigin = func(req *http.Request) bool {
			return true
		}
	}

	if o.IDGenerator == nil {
		o.IDGenerator = DefaultIDGenerator
	}
}
