package core

import (
	"bytes"
	"fmt"
	"net/http"
	u "net/url"
	"strconv"
	"strings"
	"time"

	"github.com/cdle/sillyplus/utils"
	"github.com/dop251/goja"
	"github.com/goccy/go-json"
)

func fetch(vm *goja.Runtime, wts ...interface{}) (interface{}, error) {
	var method = "get"
	var url = ""
	var req *http.Request

	var headers map[string]interface{}
	var transport *http.Transport
	var formData map[string]interface{}
	// var isJson bool
	var isJsonBody bool
	var body string
	var allow_redirects bool = true
	var responseType = ""
	// var err error
	// var useproxy bool
	var timeout time.Duration = 0
	var login = false
	for _, wt := range wts {
		switch wt := wt.(type) {
		case string:
			url = wt
		case map[string]interface{}:
			props := wt
			for i := range props {
				switch strings.ToLower(i) {
				case "timeout":
					timeout = time.Duration(utils.Int64(props[i])) * time.Millisecond
				case "headers":
					headers = props[i].(map[string]interface{})
				case "method":
					method = strings.ToLower(props[i].(string))
				case "url":
					if f, ok := props[i].(func(i goja.FunctionCall) goja.Value); ok {
						url = f(goja.FunctionCall{}).ToString().String()
					} else {
						if props[i] == nil {
							panic(Error(vm, "无效的url请求地址nil"))
						}
						url = fmt.Sprint(props[i])
					}
				case "json":
					if props[i].(bool) {
						responseType = "json"
					}
				case "responsetype":
					responseType = props[i].(string)
				case "datatype":
					responseType = props[i].(string)
				case "allowredirects":
					allow_redirects = props[i].(bool)
				case "body":
					if v, ok := props[i].(string); !ok {
						d, _ := json.Marshal(props[i])
						body = string(d)
						isJsonBody = true
					} else {
						body = v
					}
				case "login":
					login = true
				case "formdata":
					formData = props[i].(map[string]interface{})
				case "form":
					formData = props[i].(map[string]interface{})
				case "proxy":
					var url, user, password string
					for k, v := range props[i].(map[string]interface{}) {
						if k == "url" {
							url = fmt.Sprint(v)
						}
						if k == "user" {
							user = fmt.Sprint(v)
						}
						if k == "password" {
							password = fmt.Sprint(v)
						}
					}
					if url != "" {
						var err error
						transport, err = GetTransport(url, user, password)
						if err != nil {
							return nil, err
						}
					}
				}
			}
		}
		method = strings.ToUpper(method)
		var err error
		if len(formData) > 0 {
			data := u.Values{}
			for key, value := range formData {
				switch v := value.(type) {
				case string:
					data.Set(key, v)
				case bool:
					data.Set(key, strconv.FormatBool(v))
				case int:
					data.Set(key, strconv.Itoa(v))
				// 可以根据需要添加其他类型的处理
				default:
					data.Set(key, fmt.Sprintf("%v", v))
				}
			}

			req, err = http.NewRequest(method, url, strings.NewReader(data.Encode()))
			if err != nil {
				return nil, err
			}
			req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		} else {
			req, err = http.NewRequest(method, url, bytes.NewBuffer([]byte(body)))
			if err != nil {
				return nil, err
			}
			if isJsonBody {
				req.Header.Set("Content-Type", "application/json")
			}
		}
		if login {
			req.Header.Set("Cookie", "uuid=40e67d5e-f6f3-11ed-8bc2-dca9049272e5; token="+getTempAuth())
		}
		for i := range headers {
			req.Header.Set(i, fmt.Sprint(headers[i]))
		}
	}

	var rspObj goja.Proxy
	var rsp *http.Response
	var err error

	var client = &http.Client{
		Timeout: timeout,
	}
	if transport != nil {
		client.Transport = transport
	}

	if !allow_redirects {
		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		}
	}
	rsp, err = client.Do(req)
	if err != nil {
		return nil, err
	}
	defer rsp.Body.Close()
	obj, err := MakeResponseObject(vm, rsp, responseType)
	rspObj = vm.NewProxy(obj, &goja.ProxyTrapConfig{
		Get: func(target *goja.Object, property string, receiver goja.Value) (value goja.Value) {
			obj := target.Get(property)
			if obj != nil {
				return obj
			}
			switch property {
			case "statusText", "statusMessage":
				return vm.ToValue("")
			case "statusCode":
				return target.Get("status")
			// case "body":
			// 	return vm.ToValue(target.Get("getBody").Export().(func() interface{})())
			case "then":
				return goja.Undefined()
			}
			console.Error("response has no property " + property)
			return goja.Undefined()
		},
	})
	return rspObj, err
}
