package main

import (
	"log"
	"time"

	"github.com/gogo/protobuf/proto"
	"github.com/silbinarywolf/networkplatformer-go/gameclient"
	"github.com/silbinarywolf/networkplatformer-go/netmsg"
)

const (
	maxClients = 256
)

var (
	client               *Client
	isConnected          = false
	lastWorldUpdateTimer time.Time
)

type Client struct {
	*gameclient.Client
	clientSlots []*Char
}

func NewClient() *Client {
	server := &Client{
		Client:      gameclient.NewClient(),
		clientSlots: make([]*Char, maxClients),
	}
	return server
}

func (c *Client) Update() {
RecvMsgLoop:
	for {
		select {
		case buf := <-c.ChRecv():
			kind := netmsg.Kind(buf[0])
			buf = buf[1:]
			switch kind {
			case netmsg.MsgConnectResponse:
				recvMsg := &netmsg.ConnectResponse{}
				err := recvMsg.Unmarshal(buf)
				if err != nil {
					log.Fatal("marshaling error: ", err)
					break
				}

				// Receive starting pos from server and add to chars to simulate
				you.X = recvMsg.X
				you.Y = recvMsg.Y
				chars = append(chars, you)
				isConnected = true

				// Last time we received an update about the world
				lastWorldUpdateTimer = time.Now()

				log.Printf("%s: received login data: %v\n", kind, recvMsg)
			case netmsg.MsgUpdatePlayer:
				recvMsg := &netmsg.UpdatePlayer{}
				err := recvMsg.Unmarshal(buf)
				if err != nil {
					log.Fatal("marshaling error: ", err)
					break
				}
				clientSlot := recvMsg.GetClientSlot()
				char := c.clientSlots[clientSlot]
				if char == nil {
					// Create char if they don't exist
					char = &Char{}
					chars = append(chars, char)
					c.clientSlots[clientSlot] = char
				}
				char.X = recvMsg.X
				char.Y = recvMsg.Y
				char.isKeyLeftPressed = recvMsg.IsKeyLeftPressed
				char.isKeyRightPressed = recvMsg.IsKeyRightPressed
			case netmsg.MsgDisconnectPlayer:
				recvMsg := &netmsg.DisconnectPlayer{}
				err := recvMsg.Unmarshal(buf)
				if err != nil {
					log.Fatal("marshaling error: ", err)
					break
				}
				clientSlot := recvMsg.GetClientSlot()
				char := c.clientSlots[clientSlot]
				if char == nil {
					continue
				}
				char.RemoveFromSimulation()
				c.clientSlots[clientSlot] = nil
			default:
				log.Printf("Unhandled netmsg kind: %s, with data: %v", kind.String(), buf)
			}
		case <-c.ChDisconnected():
			isConnected = false
			you.RemoveFromSimulation()

			log.Println("Lost connection to server")
		default:
			// no more messages
			break RecvMsgLoop
		}
	}

	//
	if you != nil && isConnected {
		elapsed := time.Since(lastWorldUpdateTimer)
		if elapsed > 15*time.Millisecond {
			lastWorldUpdateTimer = time.Now()

			// Send update data to server
			sendMsg := netmsg.UpdatePlayer{
				X:                 you.X,
				Y:                 you.Y,
				IsKeyLeftPressed:  you.isKeyLeftPressed,
				IsKeyRightPressed: you.isKeyRightPressed,
			}
			data, err := proto.Marshal(&sendMsg)
			if err != nil {
				log.Fatal("client update: marshaling error: ", err)
			}

			// send update message to server
			packetData := make([]byte, 1, len(data)+1)
			packetData[0] = netmsg.MsgUpdatePlayer
			packetData = append(packetData, data...)
			client.SendMessage(packetData)
		}
	}
}