package main

/*
   #include <stdlib.h>
*/
import "C"
import (
	"Sunny/SunnyProxy"
	"Sunny/src/net/http"
	"bytes"
	"encoding/base64"
	"io"
	"net"
	"sync"
	"time"
	"unsafe"
)

type HTTPClient struct {
	err     error
	Context int
	http    *SunnyProxy.Winhttp
	Pointer unsafe.Pointer
	resq    *http.Response
	conn    *net.Conn
	Body    []byte
	Head    []byte
	Lock    sync.Mutex
}

var HTTPMap = make(map[int]*HTTPClient)
var HTTPMapLock sync.Mutex

//export CreateHTTPClient
// 创建 HTTP 客户端
func CreateHTTPClient() int {
	HTTPMapLock.Lock()
	HTTPMapLock.Unlock()
	w := &HTTPClient{}
	w.http = SunnyProxy.NewWinhttp()
	w.resq = new(http.Response)
	i := int(uintptr(unsafe.Pointer(w)))
	Context := GetContextID(i)
	w.Context = Context
	HTTPMapLock.Lock()
	HTTPMap[Context] = w
	HTTPMapLock.Unlock()
	return Context
}
func LoadHTTPClient(Context int) *HTTPClient {
	HTTPMapLock.Lock()
	s := HTTPMap[Context]
	HTTPMapLock.Unlock()
	if s == nil {
		return nil
	}
	return s
}

//export RemoveHTTPClient
// 释放 HTTP客户端
func RemoveHTTPClient(Context int) {

	k := LoadHTTPClient(Context)
	if k != nil {
		k.Lock.Lock()
		defer k.Lock.Unlock()
		if k.Pointer != nil {
			C.free(k.Pointer)
		}
		if k.resq != nil {
			if k.resq.Body != nil {
				_ = k.resq.Body.Close()
			}
		}
		k.Pointer = nil
		k.Body = nil
		k.http = nil
		k.Head = nil
		k.resq = nil
		k.conn = nil
		k.err = nil
		k.Context = 0
	}
	HTTPMapLock.Lock()
	delete(HTTPMap, Context)
	HTTPMapLock.Unlock()
	DelContextID(Context)
}

//export HTTPClientGetErr
//  HTTP 客户端 取错误
func HTTPClientGetErr(Context int) *C.char {
	k := LoadHTTPClient(Context)
	if k != nil {
		k.Lock.Lock()
		defer k.Lock.Unlock()
		if k.Pointer != nil {
			C.free(k.Pointer)
			k.Pointer = nil
		}
		if k.err != nil {
			n := C.CString(AuthUtf8ToGbk(k.err.Error()))
			k.Pointer = unsafe.Pointer(n)
			return n
		}
	}
	return NullString
}

//export HTTPOpen
// HTTP 客户端 Open
func HTTPOpen(Context int, mod, u *C.char) {
	k := LoadHTTPClient(Context)
	if k == nil {
		return
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.http == nil {
		return
	}
	k.http.Open(C.GoString(mod), C.GoString(u))
}

//export HTTPSetHeader
//  HTTP 客户端 设置协议头
func HTTPSetHeader(Context int, name, value *C.char) {
	k := LoadHTTPClient(Context)
	if k == nil {
		return
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.http == nil {
		return
	}
	k.http.SetHeader(C.GoString(name), C.GoString(value))
}

//export HTTPSetProxyIP
//  HTTP 客户端 设置代理IP 127.0.0.1:8888
func HTTPSetProxyIP(Context int, ip *C.char) {
	k := LoadHTTPClient(Context)
	if k == nil {
		return
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.http == nil {
		return
	}
	k.http.SetProxyIP(C.GoString(ip))
}

//export HTTPSetProxyBasicAuth
//  HTTP 客户端 设置代理IP 账号密码
func HTTPSetProxyBasicAuth(Context int, u, p *C.char) {
	k := LoadHTTPClient(Context)
	if k == nil {
		return
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.http == nil {
		return
	}
	k.http.SetProxyBasicAuth(base64.StdEncoding.EncodeToString([]byte((C.GoString(u) + ":" + C.GoString(p)))))
}

//export HTTPSetTimeouts
//  HTTP 客户端 设置超时 毫秒
func HTTPSetTimeouts(Context int, t1, t2, t3 int) {
	k := LoadHTTPClient(Context)
	if k == nil {
		return
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.http == nil {
		return
	}
	k.http.SetTimeouts(time.Duration(t1)*time.Millisecond, time.Duration(t2)*time.Millisecond, time.Duration(t3)*time.Millisecond)
}

//export HTTPSendBin
//  HTTP 客户端 发送Body
func HTTPSendBin(Context int, b uintptr, l int) {

	data := CToBytes(b, l)
	k := LoadHTTPClient(Context)
	if k == nil {
		return
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.http == nil {
		return
	}

	k.resq, k.conn, k.err = k.http.SendBin(data)

	defer func() {
		if k != nil {
			if k.resq != nil {
				if k.resq.Body != nil {
					_ = k.resq.Body.Close()
				}
			}
			if k.conn != nil && (*k.conn) != nil {
				_ = (*k.conn).Close()
			}
		}
	}()
	var B string
	if k.resq != nil {
		if k.resq.Body != nil {
			var v bytes.Buffer
			ToCh <- true
			_, _ = io.Copy(&v, k.resq.Body)
			<-ToCh
			k.Body = v.Bytes()
			_ = k.resq.Body.Close()
		}
		for name, values := range k.resq.Header {
			for _, value := range values {
				B += name + ": " + value + "\r\n"
			}
		}
	}
	k.Head = []byte(B)

}

var ToCh = make(chan bool, 300)

//export HTTPGetBodyLen
//  HTTP 客户端 返回响应长度
func HTTPGetBodyLen(Context int) int {
	k := LoadHTTPClient(Context)
	if k == nil {
		return 0
	}
	if k.Body == nil {
		return 0
	}
	return len(k.Body)
}

//export HTTPGetHeads
//  HTTP 客户端 返回响应全部Heads
func HTTPGetHeads(Context int) uintptr {
	k := LoadHTTPClient(Context)
	if k == nil {
		return 0
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.Head == nil {
		return 0
	}
	if len(k.Head) < 1 {
		return 0
	}
	return uintptr(unsafe.Pointer(&k.Head[0]))
}

//export HTTPGetBody
//  HTTP 客户端 返回响应内容
func HTTPGetBody(Context int) uintptr {
	k := LoadHTTPClient(Context)
	if k == nil {
		return 0
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.Body == nil {
		return 0
	}
	if len(k.Body) < 1 {
		return 0
	}
	return uintptr(unsafe.Pointer(&k.Body[0]))
}

//export HTTPGetCode
//  HTTP 客户端 返回响应状态码
func HTTPGetCode(Context int) int {
	k := LoadHTTPClient(Context)
	if k == nil {
		return 0
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.resq == nil {
		return 0
	}
	return k.resq.StatusCode
}

//export HTTPSetRedirect
//  HTTP 客户端 设置重定向
func HTTPSetRedirect(Context int, Redirect bool) bool {
	k := LoadHTTPClient(Context)
	if k == nil {
		return false
	}
	k.Lock.Lock()
	defer k.Lock.Unlock()
	if k.http == nil {
		return false
	}
	k.http.SetRedirect(Redirect)
	return true
}
