package netwrk

import (
	"fmt"
	"log"
	"net"
	"time"

	"github.com/google/uuid"
)

type Client struct {
	name string
	conn net.Conn
}

type ClientPool struct {
	clients map[string]Client
}

type GameClients struct {
	client1 Client
	client2 Client
}

type GameConnections struct {
	games map[string]GameClients
}

var clientPool *ClientPool
var gameConnections *GameConnections

func Listen() {
	clientPool = &ClientPool{
		clients: map[string]Client{},
	}

	gameConnections = &GameConnections{
		games: map[string]GameClients{},
	}

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

	defer listener.Close()

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Println(err)
				continue
			}

			name := make([]byte, 1024)

			n, err := conn.Read(name)
			if err != nil {
				log.Println(fmt.Sprintf("Failed to read from connection: %s", conn.LocalAddr()))
			} else {
				clientPool.clients[uuid.New().String()] = Client{
					name: string(name[:n]),
					conn: conn,
				}
			}
		}
	}()

}

func GetPool() (map[string]Client, bool) {
	if clientPool.clients != nil {
		return clientPool.clients, true
	}
	return clientPool.clients, false
}

func CreateGame(clientID1, clientID2 string) (string, error) {
	client1, ok := clientPool.clients[clientID1]
	if !ok {
		return "", fmt.Errorf("Client 1 was not found in client pool :(")
	}
	if err := client1.conn.SetWriteDeadline(time.Time{}); err != nil {
		return "", fmt.Errorf("Client 1 was not responsive")
	}

	client2, ok := clientPool.clients[clientID2]
	if !ok {
		return "", fmt.Errorf("Client 2 was not found in client pool :(")
	}
	if err := client2.conn.SetWriteDeadline(time.Time{}); err != nil {
		return "", fmt.Errorf("Client 2 was not responsive")
	}

	gameID := uuid.New().String()
	gameConnections.games[gameID] = GameClients{
		client1: client1,
		client2: client2,
	}

	delete(clientPool.clients, clientID1)
	delete(clientPool.clients, clientID2)

	return gameID, nil
}

func SendGameUpdateToClients(gameID string, bytes []byte) error {
	clients, ok := gameConnections.games[gameID]
	if !ok {
		return fmt.Errorf("Could not find game clients record")
	}

	_, err := clients.client1.conn.Write(bytes)
	if err != nil {
		return fmt.Errorf("Could not write to client1 connection")
	}
	_, err = clients.client1.conn.Write(bytes)
	if err != nil {
		return fmt.Errorf("Could not write to client2 connection")
	}

	return nil
}

func PingAndCleanLobbyClients() {
	ping := []byte("ping")

	deadClients := []string{}
	for id, client := range clientPool.clients {
		client.conn.SetWriteDeadline(time.Now().Add(time.Second))
		_, err := client.conn.Write(ping)
		if err != nil {
			log.Println("Could not write to client, deleting connection:", id)
			deadClients = append(deadClients, id)
		}
	}

	for _, id := range deadClients {
		delete(clientPool.clients, id)
	}
}