package internal

import (
	"agent/commons/debug"
	"agent/commons/utime"
	"agent/modules/ports/defines/merrs"
	"io"
	"net"
	"strconv"
	"time"
)

func connectTo(host string, port int, retryCount ...int) (conn net.Conn, err error) {
	if len(retryCount) == 0 {
		retryCount = append(retryCount, 1)
	}
	return connectTo2(host, port, retryCount[0], utime.Second*1)
}

func connectTo2(host string, port int, retryCount int, retryDelay utime.Duration) (conn net.Conn, err error) {
	if retryCount <= 0 {
		retryCount = 1
	}
	if retryDelay <= 0 {
		retryDelay = utime.Second * 1
	}
	addr := net.JoinHostPort(host, strconv.Itoa(port))
	for tryIndex := 0; tryIndex < retryCount; tryIndex++ {
		if conn, err = net.Dial("tcp", addr); err != nil {
			utime.Sleep(retryDelay)
			continue
		}
		break
	}
	if err != nil {
		return nil, merrs.Join(err, merrs.NewFailedConnectToError(addr))
	}
	debug.Logf("Connected to %s:%d", host, port)
	return conn, nil
}

func proxy(dst net.Conn, src net.Conn) error {
	buffer := make([]byte, 8*1024)
	for {
		n, readErr := src.Read(buffer)
		debug.Logf(`proxy read "%d" bytes`, n)
		if n > 0 {
			if err := dst.SetWriteDeadline(time.Now().Add(WriteTimeout)); err != nil {
				return merrs.Join(err, merrs.NewFailedSetWriteDeadlineError())
			}
			_, writeErr := dst.Write(buffer[:n])
			if writeErr != nil {
				return merrs.Join(writeErr, merrs.NewFailedWriteError())
			}
		}
		if readErr != nil {
			if readErr != io.EOF {
				return merrs.Join(readErr, merrs.NewFailedReadError())
			}
			break
		}
	}
	return nil
}
