package gnet

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"testing"
	"time"
)

func serverTCP(address string) {
	ln, err := net.Listen("tcp", address)
	if err != nil {
		panic(err)
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			_ = ln.Close()
			fmt.Println("serverTCP: accept close:", err)
			return
		}
		go func(conn net.Conn) {
			for {
				b := make([]byte, MaxBuffSize)
				n, err := conn.Read(b)
				if err != nil {
					_ = conn.Close()
					fmt.Println("conn.Read:", os.IsTimeout(err), err)
					return
				}
				fmt.Println("conn.Read:", Bytes(b[:n]).HexTo())
			}
		}(conn)
	}
}

func serverTCPModBus(address string) {
	ln, err := net.Listen("tcp", address)
	if err != nil {
		panic(err)
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			_ = ln.Close()
			fmt.Println("serverTCP: accept close:", err)
			return
		}
		go func(conn net.Conn) {
			_ = conn.SetReadDeadline(time.Now().Add(5 * time.Second))
			_ = conn.SetWriteDeadline(time.Now().Add(2 * time.Second))
			for {
				b := make([]byte, MaxBuffSize)
				n, err := conn.Read(b)
				if err != nil {
					_ = conn.Close()
					fmt.Println("conn.Read:", err)
					return
				}
				fmt.Println("conn.Read:", Bytes(b[:n]).HexTo())
				p := []byte("hello,world")
				if _, err = conn.Write(p); err != nil {
					_ = conn.Close()
					fmt.Println("conn.Write:", err)
				} else {
					fmt.Println("conn.Write:", string(p))
				}
			}
		}(conn)
	}
}

func TestTcpClient_SetAutoReconnect(t *testing.T) {
	address := "127.0.0.1:9876"
	go serverTCP(address)

	config := &Config{
		Reconnect: true,
	}
	client, err := DialTCPConfig(address, config)
	if err != nil {
		t.Error("Dial:", err)
		return
	}

	var count int
	for {
		_, err = client.Write([]byte(time.Now().String()))
		if err != nil {
			fmt.Println("client.Write:", errors.Is(err, net.ErrClosed), err)
		} else {
			count++
			if count >= 5 && count < 10 {
				time.Sleep(5 * time.Second)
			}
			if count == 10 {
				_ = client.Close()
				fmt.Println("client.Close")
			}
			if count >= 10 {
				count = 0
			}
		}
		time.Sleep(1 * time.Second)
	}
}

func TestTcpClient_SetAutoReconnectModbus(t *testing.T) {
	address := "127.0.0.1:9876"
	go serverTCPModBus(address)

	config := &Config{
		Reconnect: true,
	}
	client, err := DialTCPConfig(address, config)
	if err != nil {
		t.Error("Dial:", err)
		return
	}

	var count int
	for {
		_, err = client.Write([]byte(time.Now().String()))
		if err == nil {

			b := make([]byte, MaxBuffSize)
			n, err := client.Read(b)
			if err == nil {
				fmt.Println("client.Read:", b[:n])
				count++
				if count >= 5 && count < 10 {
					time.Sleep(5 * time.Second)
				}
				if count == 10 {
					_ = client.Close()
					fmt.Println("client.Close")
				}
				if count >= 10 {
					count = 0
				}
			} else {
				fmt.Println("client.Read:", err)
			}

		} else {
			fmt.Println("client.Write:", err)
			break
		}

		time.Sleep(1 * time.Second)
	}
}

func TestDialTCP(t *testing.T) {
	address := "127.0.0.1:9876"
	go serverTCP(address)

	client, err := DialTCP(address)
	if err != nil {
		t.Error("Dial:", err)
		return
	}

	var count int
	for {
		_, err = client.Write([]byte(time.Now().String()))
		if err != nil {
			t.Error("client.Write:", err)
			return
		}
		count++
		if count >= 5 {
			time.Sleep(6 * time.Second)
			count = 0
		} else {
			time.Sleep(1 * time.Second)
		}
	}
}

func TestDialModBus(t *testing.T) {
	address := "127.0.0.1:9876"
	go serverTCPModBus(address)

	client, err := DialTCP(address)
	if err != nil {
		t.Error("DialModBus:", err)
		return
	}

	var count int
	for {
		_, err = client.Write([]byte(time.Now().String()))
		if err != nil {
			t.Error("client.Write:", err)
			return
		}

		b := make([]byte, MaxBuffSize)
		i, err := client.Read(b)
		if err != nil {
			t.Error("client.Read:", err)
			return
		}

		fmt.Println("client.Read:", b[:i])

		count++
		if count >= 5 {
			time.Sleep(6 * time.Second)
			count = 0
		} else {
			time.Sleep(1 * time.Second)
		}
	}
}

func TestListenTCP(t *testing.T) {
	ln, err := net.Listen("tcp", "0.0.0.0:8899")
	if err != nil {
		t.Error(err)
		return
	}
	defer func() {
		_ = ln.Close()
	}()
	for {
		conn, err := ln.Accept()
		if err != nil {
			t.Error(err)
			return
		}
		go func(conn net.Conn) {
			defer func() {
				_ = conn.Close()
			}()
			for {
				b := make([]byte, 512)
				n, err := conn.Read(b)
				if err != nil {
					log.Println(err)
					return
				}
				log.Println("Hex:", Bytes(b[:n]).HexTo())
				log.Println(string(b[:n]))
			}
		}(conn)
	}
}

func TestScanner(t *testing.T) {
	conn, err := DialTCP("192.168.0.147:1000")
	if err != nil {
		t.Error(err)
		return
	}
	defer func() {
		_ = conn.Close()
	}()
	t.Log("Connected")
	time.Sleep(1 * time.Second)
	if _, err = conn.Write([]byte(`1`)); err != nil {
		t.Error(err)
		return
	}
	t.Log("Sent")
	t.Log("Reading")
	b := make([]byte, 1024)
	n, err := conn.Read(b)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log(string(b[:n]))
}

func TestGetAvailableInterfaces(t *testing.T) {
	ift, err := net.Interfaces()
	if err != nil {
		t.Error(err)
		return
	}
	for _, ifi := range ift {
		if ifi.Flags&net.FlagUp != 0 && ifi.Flags&net.FlagLoopback == 0 && ifi.Flags&net.FlagRunning != 0 {
			t.Log(ifi.Name, ifi.Flags)
		}
	}
}

func TestReadWithContext(t *testing.T) {
	listener, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() {
		_ = listener.Close()
	}()
	conn, err := net.Dial(listener.Addr().Network(), listener.Addr().String())
	if err != nil {
		t.Error(err)
		return
	}
	defer func() {
		_ = conn.Close()
	}()

	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		time.Sleep(2 * time.Second)
		cancel()
	}()

	b := make([]byte, 1024)
	n, err := ReadWithContext(ctx, conn, b)
	t.Logf("ReadWithContext: %v, %v", n, err)
}

func TestNewConnWithContext(t *testing.T) {
	listener, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() {
		_ = listener.Close()
	}()
	conn, err := net.Dial(listener.Addr().Network(), listener.Addr().String())
	if err != nil {
		t.Error(err)
		return
	}
	defer func() {
		_ = conn.Close()
	}()

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	conn = NewConnWithContext(ctx, conn)

	b := make([]byte, 1024)

	n, err := conn.Read(b)
	t.Logf("Read %d bytes, err: %v\n", n, err)
}
