package server

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
	"strconv"
)

const (
	MsgKeyPress  uint16 = 1
	MsgGameState uint16 = 2
	MSGServerStatus uint16 = 3
	MSGOnConnect uint16 = 4
)

var num_clients int = 0

func Start() {
	listener, err := net.Listen("tcp", ":9000")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Server listening on port 9000")

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("Accept error:", err)
			continue
		}

		num_clients += 1
		fmt.Println(toString(num_clients))
		go SendPacket(conn, MSGOnConnect, []byte(string(num_clients)))

		go handle(conn)
	}
}

func toString(num int) {
	return strconv.FormatInt(int64(num), 10)
}

func SendPacket(conn net.Conn, msgID uint16, payload []byte) error {
	// Length matches Lua: 2 (msgID) + payload size
	length := uint32(2 + len(payload))
	buf := make([]byte, 4+2+len(payload))

	binary.BigEndian.PutUint32(buf[0:4], length)
	binary.BigEndian.PutUint16(buf[4:6], msgID)
	copy(buf[6:], payload)

	n, err := conn.Write(buf)
	if err != nil {
		return err
	}
	if n != len(buf) {
		return fmt.Errorf("short write: expected %d bytes, got %d", len(buf), n)
	}
	return nil
}

func handle(conn net.Conn) {
	defer conn.Close()

	for {
		// Read packet length
		var length uint32

		err := binary.Read(conn, binary.BigEndian, &length)
		if err != nil {
			if err != io.EOF {
				fmt.Println("Read length error:", err)
			}

			fmt.Println("Client disconnected")
			return
		}

		// Prevent invalid packets
		if length < 2 {
			fmt.Println("Invalid packet length:", length)
			return
		}

		// Read message ID
		var msgID uint16

		err = binary.Read(conn, binary.BigEndian, &msgID)
		if err != nil {
			fmt.Println("Read message ID error:", err)
			return
		}

		// Read payload
		payload := make([]byte, length-2)

		_, err = io.ReadFull(conn, payload)
		if err != nil {
			fmt.Println("Read payload error:", err)
			return
		}

		switch msgID {

		case MsgKeyPress:
			msg := string(payload)

			fmt.Println(msg)

			// Send something back to the client
			err := SendPacket(conn, MsgGameState, []byte("received key press: "+msg))
			if err != nil {
				fmt.Println("Send error:", err)
				return
			}

		default:
			fmt.Println("Unknown message:", msgID)
		}
	}
}
