package zciyon

import (
	"io"
	"mime/multipart"
	"net/http"
	"regexp"
	"strings"
)

const (
	CIYPOST_ALLOW_TEXT = 0 //禁止任何html代码
	CIYPOST_ALLOW_HTML = 1 //允许合法html代码，但不允许js脚本
	CIYPOST_ALLOW_ALL  = 2 //全部放行
)

type CiyPost struct {
	kv  map[string]any
	W   http.ResponseWriter
	R   *http.Request
	err error
}

func NewCiyPost(w http.ResponseWriter, r *http.Request) *CiyPost {
	post := &CiyPost{}
	post.W = w
	post.R = r
	post.kv = map[string]any{}
	if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") {
		err := r.ParseMultipartForm(1024 * 5) //1024 * 1024 * 1024 *
		if err != nil {
			post.err = err
		} else {
			for k, v := range r.Form {
				post.kv[k] = v[0]
			}
			if r.MultipartForm != nil && r.MultipartForm.File != nil {
				for k, files := range r.MultipartForm.File {
					post.kv[k] = files[0]
				}
			}
		}
	} else if r.Method == "POST" {
		body, err := io.ReadAll(r.Body)
		if err != nil {
			post.err = err
		} else {
			post.kv = Byte_JSON(body)
			if len(post.kv) == 0 {
				post.kv = map[string]any{"body": string(body)}
			}
		}
	}
	for k, v := range r.URL.Query() {
		post.kv[k] = v[0]
	}
	if len(post.kv) == 0 {
		post.kv[""] = r.URL.RawQuery
	}
	return post
}

func (thos *CiyPost) Is(key string) bool {
	_, ok := thos.kv[key]
	return ok
}
func (thos *CiyPost) Getany(key string) any {
	return thos.kv[key]
}
func (thos *CiyPost) Getobj(key string) map[string]any {
	if arr, ok := thos.kv[key].(map[string]any); ok {
		return arr
	}
	return map[string]any{}
}
func (thos *CiyPost) Getint(key string, argdef ...int) int {
	return Toint(thos.kv[key], argdef...)
}
func (thos *CiyPost) Getfloat(key string, argdef ...float64) float64 {
	return Tofloat(thos.kv[key], argdef...)
}
func (thos *CiyPost) Getbool(key string, argdef ...bool) bool {
	return Tobool(thos.kv[key], argdef...)
}
func (thos *CiyPost) Getdate(key string) int {
	return Tostamp(Tostr(thos.kv[key]))
}
func (thos *CiyPost) GetIP() string {
	xForwardedFor := thos.R.Header.Get("X-Forwarded-For")
	if xForwardedFor != "" {
		return strings.TrimSpace(strings.Split(xForwardedFor, ",")[0])
	}
	xRealIP := thos.R.Header.Get("X-Real-IP")
	if xRealIP != "" {
		return xRealIP
	}
	return thos.R.RemoteAddr
}
func (thos *CiyPost) IsWeixin() bool {
	useragent := thos.R.Header.Get("HTTP_USER_AGENT")
	useragent = strings.ToLower(useragent)
	return strings.Contains(useragent, "micromessenger")
}

func (thos *CiyPost) Get(key string, args ...any) string {
	allow := CIYPOST_ALLOW_TEXT
	defval := ""
	for _, arg := range args {
		switch v := arg.(type) {
		case int:
			allow = v
		case string:
			defval = v
		}
	}
	str := Tostr(thos.kv[key])
	if allow == CIYPOST_ALLOW_TEXT {
		str = strings.TrimSpace(thos.triptotext(str))
	} else if allow == CIYPOST_ALLOW_HTML {
		str = thos.triptohtml(str)
		//str = template.HTMLEscapeString(str)
		//str = template.JSEscapeString(str)
	}
	if str == "" {
		return defval
	}
	return str
}
func (thos *CiyPost) Gets(key string, args ...any) []string {
	allow := CIYPOST_ALLOW_TEXT
	for _, arg := range args {
		switch v := arg.(type) {
		case int:
			allow = v
		}
	}
	switch v := thos.kv[key].(type) {
	case []any:
		strs := make([]string, len(v))
		for i, s := range v {
			str := Tostr(s)
			if allow == CIYPOST_ALLOW_TEXT {
				str = strings.TrimSpace(thos.triptotext(str))
			} else if allow == CIYPOST_ALLOW_HTML {
				str = thos.triptohtml(str)
			}
			strs[i] = str
		}
		return strs
	}
	return []string{""}
}
func (thos *CiyPost) Getfile(argkey ...string) *multipart.FileHeader {
	key := ""
	if len(argkey) > 0 {
		key = argkey[0]
	}
	if key != "" {
		switch v := thos.kv[key].(type) {
		case *multipart.FileHeader:
			return v
		}
	} else {
		for _, kv := range thos.kv {
			switch v := kv.(type) {
			case *multipart.FileHeader:
				return v
			}
		}
	}
	return nil
}
func (thos *CiyPost) triptotext(str string) string { //去掉所有html标签和控制字符
	re, _ := regexp.Compile(`\<[\S\s]+?\>`) //标签小写
	str = re.ReplaceAllStringFunc(str, strings.ToLower)
	re, _ = regexp.Compile(`\<style[\S\s]+?\</style\>`) //删除style
	str = re.ReplaceAllString(str, "")
	re, _ = regexp.Compile(`\<script[\S\s]+?\</script\>`) //删除script
	str = re.ReplaceAllString(str, "")
	re, _ = regexp.Compile(`\<[\S\s]+?\>`) //删除标签
	str = re.ReplaceAllString(str, "")
	return str
}
func (thos *CiyPost) triptohtml(str string) string { //保留html标签和style属性。去掉所有事件、style、script
	re, _ := regexp.Compile(`\<[\S\s]+?\>`) //标签小写
	str = re.ReplaceAllStringFunc(str, strings.ToLower)
	re, _ = regexp.Compile(`\<style[\S\s]+?\</style\>`) //删除style
	str = re.ReplaceAllString(str, "")
	re, _ = regexp.Compile(`\<script[\S\s]+?\</script\>`) //删除script
	str = re.ReplaceAllString(str, "")
	reOnEvent := regexp.MustCompile(` on\w+="[^"]*"`) //删除双引号事件
	str = reOnEvent.ReplaceAllString(str, "")
	reOnEvent2 := regexp.MustCompile(` on\w+='[^"]*'`) //删除单引号事件
	str = reOnEvent2.ReplaceAllString(str, "")
	reOnEvent3 := regexp.MustCompile(` on\w+=`) //破坏事件代码
	str = reOnEvent3.ReplaceAllString(str, " ")
	return str
}
