package forwarder

import (
	"crypto/tls"
	"errors"
	"github.com/tobyxdd/hysteria/internal/forwarder"
	"net"
)

type client struct {
	qc *forwarder.QUICClient
}

func NewClient(localAddr string, remoteAddr string, config ClientConfig, callbacks ClientCallbacks) (Client, error) {
	// Fix config first
	if config.Speed == nil || config.Speed.SendBPS == 0 || config.Speed.ReceiveBPS == 0 {
		return nil, errors.New("invalid speed")
	}
	if config.TLSConfig == nil {
		config.TLSConfig = &tls.Config{NextProtos: []string{TLSAppProtocol}}
	}
	if config.MaxReceiveWindowPerConnection == 0 {
		config.MaxReceiveWindowPerConnection = defaultReceiveWindowConn
	}
	if config.MaxReceiveWindow == 0 {
		config.MaxReceiveWindow = defaultReceiveWindow
	}
	qc, err := forwarder.NewQUICClient(localAddr, remoteAddr, config.Name, config.TLSConfig,
		config.Speed.SendBPS, config.Speed.ReceiveBPS,
		config.MaxReceiveWindowPerConnection, config.MaxReceiveWindow,
		forwarder.CongestionFactory(config.CongestionFactory),
		func(addr net.Addr, banner string, cSend uint64, cRecv uint64) {
			if callbacks.ServerConnectedCallback != nil {
				callbacks.ServerConnectedCallback(addr, banner, cSend, cRecv)
			}
		},
		func(err error) {
			if callbacks.ServerErrorCallback != nil {
				callbacks.ServerErrorCallback(err)
			}
		},
		func(addr net.Addr) {
			if callbacks.NewTCPConnectionCallback != nil {
				callbacks.NewTCPConnectionCallback(addr)
			}
		},
		func(addr net.Addr, err error) {
			if callbacks.TCPConnectionClosedCallback != nil {
				callbacks.TCPConnectionClosedCallback(addr, err)
			}
		},
	)
	if err != nil {
		return nil, err
	}
	return &client{qc: qc}, nil
}

func (c *client) Stats() Stats {
	addr, in, out := c.qc.Stats()
	return Stats{
		RemoteAddr:    addr,
		inboundBytes:  in,
		outboundBytes: out,
	}
}

func (c *client) Close() error {
	return c.Close()
}