import io
import net
import strings

const (
	server_port = ':22443'
)

fn accept(mut server net.TcpListener, c chan &net.TcpConn) {
	c <- server.accept() or { panic(err) }
}

fn setup() (&net.TcpListener, &net.TcpConn, &net.TcpConn) {
	mut server := net.listen_tcp(.ip6, server_port) or { panic(err) }

	c := chan &net.TcpConn{}
	spawn accept(mut server, c)
	mut client := net.dial_tcp('localhost${server_port}') or { panic(err) }

	socket := <-c

	$if debug_peer_ip ? {
		eprintln('${server.addr()}\n${client.peer_addr()}, ${client.addr()}\n${socket.peer_addr()}, ${socket.addr()}')
	}
	assert true
	return server, client, socket
}

fn cleanup(mut server net.TcpListener, mut client net.TcpConn, mut socket net.TcpConn) {
	server.close() or {}
	client.close() or {}
	socket.close() or {}
}

fn test_socket() {
	mut server, mut client, mut socket := setup()
	defer {
		cleanup(mut server, mut client, mut socket)
	}
	message := 'Hello World'
	socket.write_string(message) or {
		assert false
		return
	}
	assert true
	$if debug {
		println('message send: ${message}')
	}
	$if debug {
		println('send socket: ${socket.sock.handle}')
	}
	mut buf := []u8{len: 1024}
	nbytes := client.read(mut buf) or {
		assert false
		return
	}
	received := buf[0..nbytes].bytestr()
	$if debug {
		println('message received: ${received}')
	}
	$if debug {
		println('client: ${client.sock.handle}')
	}
	assert message == received
}

fn test_socket_write_and_read() {
	mut server, mut client, mut socket := setup()
	defer {
		cleanup(mut server, mut client, mut socket)
	}
	message1 := 'a message 1'
	socket.write_string(message1) or { assert false }
	mut rbuf := []u8{len: message1.len}
	client.read(mut rbuf) or {
		assert false
		return
	}
	line := rbuf.bytestr()
	assert line == message1
}

fn test_socket_read_line() {
	mut server, mut client, mut socket := setup()
	mut reader := io.new_buffered_reader(reader: client)
	defer {
		cleanup(mut server, mut client, mut socket)
	}
	message1, message2 := 'message1', 'message2'
	message := '${message1}\n${message2}\n'
	socket.write_string(message) or { assert false }
	assert true
	//
	line1 := reader.read_line() or {
		// println(reader.buf)
		assert false
		return
	}
	line2 := reader.read_line() or {
		// println(reader.buf)
		assert false
		return
	}
	assert line1 == message1
	assert line2 == message2
}

fn test_socket_write_fail_without_panic() {
	mut server, mut client, mut socket := setup()
	defer {
		cleanup(mut server, mut client, mut socket)
	}
	message2 := 'a message 2'
	// ensure that socket.write (i.e. done on the server side)
	// continues to work, even when the client side has been disconnected
	// this test is important for a stable long standing server
	client.close() or {}
	$if solaris {
		return
	}
	$if freebsd {
		return
	}
	// TODO: fix segfaulting on Solaris and FreeBSD
	for i := 0; i < 3; i++ {
		socket.write_string(message2) or {
			println('write to a socket without a recipient should produce an option fail: ${err} | ${message2}')
			assert true
		}
	}
}

fn test_socket_read_line_long_line_without_eol() {
	mut server, mut client, mut socket := setup()
	mut reader := io.new_buffered_reader(reader: client)
	defer {
		cleanup(mut server, mut client, mut socket)
	}
	message := strings.repeat_string('123', 400)
	socket.write_string(message) or {
		assert false
		return
	}
	socket.write_string('\n') or {
		assert false
		return
	}
	line := reader.read_line() or {
		assert false
		return
	}
	assert line == message
}
