package yu_tcp

import (
	yu_base64 "gogs.qqck.cn/s/tools/base64"
	yu_fast "gogs.qqck.cn/s/tools/fast"
	yu_proxy "gogs.qqck.cn/s/tools/proxy"
	yu_strconv "gogs.qqck.cn/s/tools/strconv"
	"net"
	"net/netip"
)

type Tcp struct {
	host string // IP 或 域名
	port int    // 端口号

	proxy *yu_proxy.Info

	sec  int32 // 超时时间，单位：秒
	usec int32 // 超时时间，单位：微妙

	fd uintptr // socket 句柄
}

// New
//
//	@Description:  创建 Tcp 对象
func New() (t *Tcp) {
	t = &Tcp{}
	t.SetSec(30)
	t.SetUsec(0)
	t.init()
	return
}

func (t *Tcp) SetHost(value string) *Tcp {
	t.host = value
	return t
}

func (t *Tcp) GetHost() string {
	return t.host
}

func (t *Tcp) SetPort(value int) *Tcp {
	t.port = value
	return t
}

func (t *Tcp) GetPort() int {
	return t.port
}

func (t *Tcp) SetProxy(value *yu_proxy.Info) *Tcp {
	t.proxy = value
	return t
}

func (t *Tcp) GetProxy() *yu_proxy.Info {
	return t.proxy
}

// SetSec
//
//	@Description: 设置超时时间，单位：秒，默认：30 ，最终的超时时间是 sec 和 usec 的总和
func (t *Tcp) SetSec(value int32) *Tcp {
	t.sec = value
	return t
}

func (t *Tcp) GetSec() int32 {
	return t.sec
}

// SetUsec
//
//	@Description: 设置超时时间，单位：微秒，默认：0，最终的超时时间是 sec 和 usec 的总和
func (t *Tcp) SetUsec(value int32) *Tcp {
	t.usec = value
	return t
}

func (t *Tcp) GetUsec() int32 {
	return t.usec
}

func (t *Tcp) Connect() bool {
	if t.proxy != nil && t.proxy.IsValid() {
		return t.content_proxy()
	}
	return t.connect(t.host, t.port)
}

func (t *Tcp) content_proxy() bool {
	if t.proxy.IsTimeout() {
		return false
	}
	if !t.connect(t.proxy.Host, t.proxy.Port) {
		return false
	}
	var j_addr netip.Addr
	var j_err error
	var j_doamin bool
	if j_addr, j_err = netip.ParseAddr(t.host); j_err != nil {
		j_addrs, j_err := net.LookupHost(t.host)
		if j_err != nil || len(j_addrs) == 0 {
			t.Close()
			return false
		}
		if j_addr, j_err = netip.ParseAddr(j_addrs[0]); j_err != nil {
			t.Close()
			return false
		}
		j_doamin = true
	}
	if t.proxy.IsHttp() {
		j_buf := make([]byte, 0, 256)
		j_buf = append(j_buf, "CONNECT "...)
		if t.proxy.Domain {
			j_buf = append(j_buf, t.host...)
		} else if j_addr.IsValid() {
			if j_addr.Is4() {
				j_buf = append(j_buf, j_addr.String()...)
			} else if j_addr.Is6() {
				j_buf = append(j_buf, '[')
				j_buf = append(j_buf, j_addr.String()...)
				j_buf = append(j_buf, ']')
			} else {
				t.Close()
				return false
			}
		} else {
			t.Close()
			return false
		}
		j_buf = append(j_buf, ':')
		j_buf = append(j_buf, yu_strconv.FormatInt(t.port)...)
		j_buf = append(j_buf, " HTTP/1.1\r\n"...)
		j_buf = append(j_buf, "Proxy-Connection: Keep-Alive"...)
		j_buf = append(j_buf, 13, 10)
		if t.proxy.IsAuthorization() {
			j_buf = append(j_buf, "Proxy-Authorization: Basic "...)
			j_buf = append(j_buf, yu_base64.Std.EncodeS2S(t.proxy.User+":"+t.proxy.Pass)...)
			j_buf = append(j_buf, 13, 10)
		}
		j_buf = append(j_buf, 13, 10)
		if !t.send(t.fd, j_buf) {
			t.Close()
			return false
		}

		if j_buf = t.recv(t.fd, 1024); len(j_buf) == 0 {
			t.Close()
			return false
		}
		// "HTTP/1.1 200 Connection Established"、"HTTP/1.1 200 Connection established"
		// HTTP/1.0 200 OK
		if len(j_buf) < 36 || yu_fast.B2S(j_buf[9:12]) != "200" {
			t.Close()
			return false
		}
		switch yu_fast.B2S(j_buf[13:35]) {
		case "Connection Established", "Connection established", "connection Established", "connection established":
		default:
			t.Close()
			return false
		}
		return true
	}
	if t.proxy.IsSocks5() {
		// https://zhuanlan.zhihu.com/p/458173597?utm_id=0
		// https://www.jianshu.com/p/97873541510f
		j_buf := make([]byte, 0, 256)
		j_buf = append(j_buf, 5) // VER 协议版本号
		j_buf = append(j_buf, 1) // NMETHODS 客户端支持的认证方法数量
		// X'00' 不需要身份验证(NO AUTHENTICATION REQUIRED)
		// X'01' GSSAPI
		// X'02' 用户密码认证(USERNAME/PASSWORD)
		// X'03' to X'7F' IANA ASSIGNED
		// X'80' to X'FE' RESERVED FOR PRIVATE METHODS
		if t.proxy.IsAuthorization() {
			j_buf = append(j_buf, 0x02) // METHODS：认证方法
		} else {
			j_buf = append(j_buf, 0x00) // METHODS：认证方法
		}
		if !t.send(t.fd, j_buf) {
			t.Close()
			return false
		}
		if j_buf = t.recv(t.fd, 1024); len(j_buf) == 0 {
			t.Close()
			return false
		}
		if len(j_buf) != 2 || j_buf[0] != 5 {
			t.Close()
			return false
		}
		if j_buf[1] == 0x02 {
			j_buf = append(j_buf[0:0], 1) // VERSION 认证子协商版本（与SOCKS协议版本的0x05无关系）
			j_buf = append(j_buf, byte(len(t.proxy.User)))
			j_buf = append(j_buf, t.proxy.User...)
			j_buf = append(j_buf, byte(len(t.proxy.Pass)))
			j_buf = append(j_buf, t.proxy.Pass...)
			if !t.send(t.fd, j_buf) {
				t.Close()
				return false
			}
			if j_buf = t.recv(t.fd, 1024); len(j_buf) == 0 {
				t.Close()
				return false
			}
			if len(j_buf) != 2 || (j_buf[0] != 1 && j_buf[0] != 5) || j_buf[1] != 0 {
				t.Close()
				return false
			}
		} else if j_buf[1] != 0x00 {
			t.Close()
			return false
		}
		j_buf = append(j_buf[0:0], 5) // VER 协议版本号
		j_buf = append(j_buf, 0x01)   // 0x01 CONNECT 连接目标服务器
		j_buf = append(j_buf, 0)      // RSV 保留字段
		if t.proxy.Domain && j_doamin {
			j_buf = append(j_buf, 0x03) // 0x03 域名地址(没有打错，就是没有0x02)，域名地址的第1个字节为域名长度，剩下字节为域名名称字节数组
			j_buf = append(j_buf, byte(len(t.host)))
			j_buf = append(j_buf, t.host...)
		} else if j_addr.IsValid() {
			if j_addr.Is4() {
				j_buf = append(j_buf, 0x01) // 0x01 IP V4地址
			} else if j_addr.Is6() {
				j_buf = append(j_buf, 0x04) // 0x04 IP V6地址
			} else {
				t.Close()
				return false
			}
			j_buf = append(j_buf, j_addr.AsSlice()...)
		} else {
			t.Close()
			return false
		}
		j_buf = append(j_buf, byte(t.port>>8), byte(t.port))
		if !t.send(t.fd, j_buf) {
			t.Close()
			return false
		}
		if j_buf = t.recv(t.fd, 1024); len(j_buf) == 0 {
			t.Close()
			return false
		}
		if len(j_buf) < 10 || j_buf[0] != 5 || j_buf[1] != 0 || j_buf[2] != 0 {
			t.Close()
			return false
		}
		return true
	}
	return true
}

func (t *Tcp) Send(buf []byte) bool {
	return t.send(t.fd, buf)
}

func (t *Tcp) Recv(size int) []byte {
	return t.recv(t.fd, size)
}

type Pack byte

const (
	// PackV1 头四字节包含长度信息(包含长度信息自身的四字节)，长度信息为高位字序，如： 00 00 00 09 11 22 33 44 55
	PackV1 Pack = iota
)

func (t *Tcp) SendPack(v Pack, buf []byte) bool {
	switch v {
	case PackV1:
		j_buf := make([]byte, len(buf)+4)
		j_buf[0] = byte(len(j_buf) >> 24)
		j_buf[1] = byte(len(j_buf) >> 16)
		j_buf[2] = byte(len(j_buf) >> 8)
		j_buf[3] = byte(len(j_buf))
		copy(j_buf[4:], buf)
		return t.send(t.fd, j_buf)
	default:
		return false
	}
}

// RecvPack
//
//	@Description: 如果接收失败返回 nil ，如果接收成功但数据包体长度为 0 返回 make([]byte, 0)
func (t *Tcp) RecvPack(v Pack) []byte {
	switch v {
	case PackV1:
		var j_buf = make([]byte, 0, 4)
		for len(j_buf) != cap(j_buf) {
			j_tmp := t.recv(t.fd, cap(j_buf)-len(j_buf))
			if len(j_tmp) == 0 {
				return nil
			}
			j_buf = append(j_buf, j_tmp...)
		}
		j_size := int(int32(j_buf[3]) | int32(j_buf[2])<<8 | int32(j_buf[1])<<16 | int32(j_buf[0])<<24)
		j_size -= 4
		if j_size < 0 {
			return nil
		}
		j_buf = make([]byte, 0, j_size)
		for len(j_buf) != cap(j_buf) {
			j_tmp := t.recv(t.fd, cap(j_buf)-len(j_buf))
			if len(j_tmp) == 0 {
				return nil
			}
			j_buf = append(j_buf, j_tmp...)
		}
		return j_buf
	default:
		return nil
	}
}

func (t *Tcp) Close() *Tcp {
	t.close()
	return t
}
