package webServer

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"
	"time"

	"goutil/logUtil"
	"goutil/typeUtil"
)

var (
	defaultPageMap = make(map[string]bool)
)

func init() {
	defaultPageMap["/"] = true
	defaultPageMap["/favicon.ico"] = true
}

// web服务对象
type WebServer struct {
	// 所有对外提供的处理器集合
	handlerMap map[string]*handler

	// 需要应用的Header集合
	headerMap map[string]string

	// 指定的HTTP请求方法，如果不指定则任意方法均有效
	specifiedMethod string

	// 当HTTP请求方法无效时，调用的处理器
	invalidMethodHandler func(*Context)

	// 默认页的处理器（默认页指的是/或/favicon.ico，通常是被负载均衡器调用或在浏览器中直接访问，而不会被程序调用）
	defaultPageHandler func(*Context)

	// 未找到指定的回调时的处理器，通常是因为该url是可变的，而不是固定的
	notFoundPageHandler func(*Context)

	// 未处理的异常处理函数
	unHandledPanicHandler func(context *Context, errObj interface{})

	// ifDelegate:是否经过负责均衡中转（经过负载均衡中转后，Request的地址需要从Header获取）
	ifDelegate bool

	// 在Debug模式下是否需要验证IP地址，默认情况下不验证
	ifCheckIPWhenDebug bool

	// 当IP无效时调用的处理器
	ipInvalidHandler func(*Context)

	// 用于检测参数是否有效的处理器
	paramCheckHandler func(typeUtil.MapData, []string, []string) ([]string, []string, bool)

	// 当检测到参数无效时调用的处理器
	paramInvalidHandler func(*Context, []string, []string)

	// 处理请求数据的处理器（例如压缩、解密等）
	requestDataHandler func(*Context, []byte) ([]byte, error)

	// 处理响应数据的处理器（例如压缩、加密等）
	responseDataHandler func(*Context, []byte) ([]byte, error)

	// 请求执行时间的处理器
	executeTimeHandler func(*Context)
}

// 注册API
// path：注册的访问路径
// callback：回调方法
// configObj：Handler配置对象
func (this *WebServer) RegisterHandler(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig) {
	// 判断是否已经注册过，避免命名重复
	if _, exist := this.handlerMap[path]; exist {
		panic(fmt.Sprintf("%s has been registered, please try a new path", path))
	}

	this.handlerMap[path] = newHandler(path, handlerFuncObj, configObj)
}

// 注册回调-增加用户自定义数据
func (this *WebServer) RegisterHandlerWithUserData(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig, userData interface{}) {
	// 判断是否已经注册过，避免命名重复
	if _, exist := this.handlerMap[path]; exist {
		panic(fmt.Sprintf("%s has been registered, please try a new path", path))
	}

	handler := newHandler(path, handlerFuncObj, configObj)
	handler.userData = userData
	this.handlerMap[path] = handler
}

// 注册正则表式路径API
// path：注册的访问路径
// callback：回调方法
// configObj：Handler配置对象
func (this *WebServer) RegisterRegexHandler(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig) {
	// 判断是否已经注册过，避免命名重复
	if _, exist := this.handlerMap[path]; exist {
		panic(fmt.Sprintf("%s has been registered, please try a new path", path))
	}

	handler := newHandler(path, handlerFuncObj, configObj)
	handler.regex = true
	this.handlerMap[path] = handler
}

// 注册正则回调-增加用户自定义数据
func (this *WebServer) RegisterRegexHandlerWithUserData(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig, userData interface{}) {
	// 判断是否已经注册过，避免命名重复
	if _, exist := this.handlerMap[path]; exist {
		panic(fmt.Sprintf("%s has been registered, please try a new path", path))
	}

	handler := newHandler(path, handlerFuncObj, configObj)
	handler.userData = userData
	handler.regex = true
	this.handlerMap[path] = handler
}

// 获取请求方法
// path:方法名称
// 返回值:
// 请求方法
// 是否存在
func (this *WebServer) getHandler(path string) (handlerObj *handler, exist bool) {
	handlerObj, exist = this.handlerMap[path]

	if !exist {
		for _, handler := range this.handlerMap {
			if handler.regex {
				match, _ := regexp.MatchString(handler.path, path)
				if match {
					return handler, true
				}
			}
		}
	}
	return
}

// 设定Http Header信息
func (this *WebServer) SetHeader(header map[string]string) {
	this.headerMap = header
}

// 处理Http Header信息
func (this *WebServer) handleHeader(context *Context) {
	if this.headerMap != nil && len(this.headerMap) > 0 {
		for k, v := range this.headerMap {
			context.responseWriter.Header().Set(k, v)
		}
	}
}

// 设定HTTP请求方法
func (this *WebServer) SetMethod(method string) {
	this.specifiedMethod = method
}

// 设定当HTTP请求方法无效时，调用的处理器
func (this *WebServer) SetInvalidMethodHandler(handler func(*Context)) {
	this.invalidMethodHandler = handler
}

// 处理HTTP请求方法
// 返回值
// isTerminate:是否终止本次请求
func (this *WebServer) handleMethod(context *Context) (isTerminate bool) {
	if this.specifiedMethod != "" {
		if context.request.Method != this.specifiedMethod {
			if this.invalidMethodHandler != nil {
				this.invalidMethodHandler(context)
			} else {
				http.Error(context.responseWriter, fmt.Sprintf("Expected %s Method", this.specifiedMethod), 406)
			}
			isTerminate = true
		}
	}

	return
}

// 设定默认页的处理器
func (this *WebServer) SetDefaultPageHandler(handler func(*Context)) {
	this.defaultPageHandler = handler
}

// 处理默认页
// 返回值
// isTerminate:是否终止本次请求
func (this *WebServer) handleDefaultPage(context *Context) (isTerminate bool) {
	// 首页进行特别处理
	if _, exist := defaultPageMap[context.GetRequestPath()]; exist {
		if this.defaultPageHandler != nil {
			this.defaultPageHandler(context)
		} else {
			context.WriteString("Welcome to home page.")
		}
		isTerminate = true
	}

	return
}

// 设定未找到指定的回调时的处理器
func (this *WebServer) SetNotFoundPageHandler(handler func(*Context)) {
	this.notFoundPageHandler = handler
}

// 设置异常处理函数（默认只会记录在文件）
func (this *WebServer) SetUnHandledPanicHandler(handler func(context *Context, errObj interface{})) {
	this.unHandledPanicHandler = handler
}

// 设定在Debug模式下是否需要验证IP地址
func (this *WebServer) SetIfCheckIPWhenDebug(value bool) {
	this.ifCheckIPWhenDebug = value
}

// 设定当IP无效时调用的处理器
func (this *WebServer) SetIPInvalidHandler(handler func(*Context)) {
	this.ipInvalidHandler = handler
}

// 设定用于检测参数是否有效的处理器
func (this *WebServer) SetParamCheckHandler(handler func(typeUtil.MapData, []string, []string) ([]string, []string, bool)) {
	this.paramCheckHandler = handler
}

// 设定当检测到参数无效时调用的处理器
func (this *WebServer) SetParamInvalidHandler(handler func(*Context, []string, []string)) {
	this.paramInvalidHandler = handler
}

// 设定处理请求数据的处理器（例如压缩、解密等）
func (this *WebServer) SetRequestDataHandler(handler func(*Context, []byte) ([]byte, error)) {
	this.requestDataHandler = handler
}

// 设定处理响应数据的处理器（例如压缩、加密等）
func (this *WebServer) SetResponseDataHandler(handler func(*Context, []byte) ([]byte, error)) {
	this.responseDataHandler = handler
}

// 设定请求执行时间的处理器
func (this *WebServer) SetExecuteTimeHandler(handler func(*Context)) {
	this.executeTimeHandler = handler
}

// 处理请求执行时间逻辑
func (this *WebServer) handleExecuteTime(context *Context) {
	if this.executeTimeHandler != nil {
		this.executeTimeHandler(context)
	}
}

// 设置WebServer请求是否经过了负载均衡中转
func (this *WebServer) SetIfDelegate(ifDelegate bool) {
	this.ifDelegate = ifDelegate
}

// http应答处理
// responseWriter:应答对象
// request:请求对象
func (this *WebServer) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) {
	// 构造上下文对象
	context := newContext(request, responseWriter, this.requestDataHandler, this.responseDataHandler, this.ifDelegate)
	defer func() {
		if r := recover(); r != nil {
			if this.unHandledPanicHandler != nil {
				this.unHandledPanicHandler(context, r)
			} else {
				logUtil.LogUnknownError(r)
			}
		}
	}()

	// 处理Http Header信息
	this.handleHeader(context)

	// 处理默认页
	if this.handleDefaultPage(context) {
		return
	}

	// 处理返回值信息
	defer func() {
		// 处理请求执行时间逻辑
		this.handleExecuteTime(context)
	}()

	// 处理请求方法
	if this.handleMethod(context) {
		return
	}

	// 根据路径选择不同的处理方法
	var handlerObj *handler
	var exist bool
	if handlerObj, exist = this.getHandler(context.GetRequestPath()); !exist {
		if this.notFoundPageHandler != nil {
			this.notFoundPageHandler(context)
		} else {
			http.Error(context.responseWriter, "访问的页面不存在", 404)
		}
		return
	}

	// 将用户自定义数据通过Context传入回调
	context.userData = handlerObj.userData

	// Check IP
	if handlerObj.checkIP(context, this.ifCheckIPWhenDebug) == false {
		if this.ipInvalidHandler != nil {
			this.ipInvalidHandler(context)
		} else {
			http.Error(context.responseWriter, "你的IP不允许访问，请联系管理员", 401)
		}
		return
	}

	// Check Param
	if missParamList, emptyParamList, valid := handlerObj.checkParam(context, this.specifiedMethod, this.paramCheckHandler); valid == false {
		if this.paramInvalidHandler != nil {
			this.paramInvalidHandler(context, missParamList, emptyParamList)
		} else {
			if missParamList != nil && len(missParamList) > 0 {
				http.Error(context.responseWriter, fmt.Sprintf("你的参数不正确，请检查，缺少以下参数:%s", strings.Join(missParamList, ",")), 500)
			} else {
				http.Error(context.responseWriter, fmt.Sprintf("你的参数不正确，请检查，以下参数为空:%s", strings.Join(emptyParamList, ",")), 500)
			}
		}
		return
	}

	// Call Function
	handlerObj.funcObj(context)

	context.EndTime = time.Now()
}

// 新建WebServer对象
// isCheckIP:该属性已丢弃，可以任意赋值
func NewWebServer(isCheckIP bool) *WebServer {
	return &WebServer{
		handlerMap: make(map[string]*handler),
		headerMap:  make(map[string]string),
	}
}
