package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"math/rand"
	"net/http"
	"os"
	"time"
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()

	player := &Player{
		Id:         fmt.Sprintf("%d", rand.Int()),
		RoomId:     "",
		Color:      -1,
		Speed:      200,
		UpdatedAt:  0,
		X:          0,
		Y:          0,
		Dx:         0,
		Dy:         0,
		Tail:       nil,
		Connection: c,
		LastInput:  PlayerInput{Direction: 0},
	}

	var room *Room
	var tail []XY
	var colors []int

	roomsLock.Lock()

	rand.Shuffle(len(rooms), func(i, j int) {
		rooms[i], rooms[j] = rooms[j], rooms[i]
	})

	for _, r := range rooms {
    r.Lock.Lock()

		if !r.IsClosed && len(r.Players) < r.MaxPlayers && time.Now().Sub(r.CreatedAt) < 5 * time.Minute {
			colors = r.GetAvailableColors()
			if len(colors) == 0 {
        r.Lock.Unlock()
				continue
			}

			tail = r.GetNewPlayerTail()
			if tail == nil || len(tail) == 0 {
        r.Lock.Unlock()
				continue
			}

			room = r
			break
		}
	}

  isNewRoom := false
	if room == nil || colors == nil || tail == nil {
		room = NewRoom()
		rooms = append(rooms, room)

		room.Lock.Lock()

		colors = room.GetAvailableColors()
		tail = room.GetNewPlayerTail()

    isNewRoom = true
	}

	player.Tail = tail
	player.X = tail[0].X
	player.Y = tail[0].Y

	if tail[0].X < tail[1].X {
		player.Dx = -1
		player.Dy = 0
	} else if tail[0].X > tail[1].X {
		player.Dx = 1
		player.Dy = 0
	} else if tail[0].Y < tail[1].Y {
		player.Dx = 0
		player.Dy = -1
	} else if tail[0].Y > tail[1].Y {
		player.Dx = 0
		player.Dy = 1
	}

	player.RoomId = room.Id
	player.Color = colors[rand.Int()%len(colors)]

	room.Players = append(room.Players, player)

	room.Lock.Unlock()
	roomsLock.Unlock()

  if isNewRoom {
    go room.Process()
  }

	defer func() {
		player.GameOver = true
    log.Println("Player disconnected", player.Id, r.Header.Get("X-Forwarded-For"), room.Id)
	}()

  log.Println("Player connected", player.Id, r.Header.Get("X-Forwarded-For"), room.Id)

	for {
		_, message, err := c.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			break
		}

		roomsLock.Lock()
		if err = json.Unmarshal(message, &player.LastInput); err != nil {
			roomsLock.Unlock()
			log.Println(err)
			break
		}
		roomsLock.Unlock()
	}
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "80"
	}

	rand.Seed(time.Now().UnixNano())

	log.SetFlags(0)
	http.Handle("/", http.FileServer(http.Dir("./static")))
	http.HandleFunc("/ws", wsHandler)

//	go ProcessRooms()

	log.Fatal(http.ListenAndServe(":" + port, nil))
}
