package gameserver

import (
	"battlecamp-go-server/game"
	"battlecamp-go-server/player"
	"battlecamp-go-server/stomp"
	"encoding/json"
	"log"
	"net/http"
	"runtime/pprof"
	"strconv"

	"github.com/julienschmidt/httprouter"
)

var gameServer *GameServer

func newUrlRouter(gs *GameServer) *httprouter.Router {
	gameServer = gs

	router := httprouter.New()
	router.GET("/", showIndex)
	router.GET("/games", listGames)
	router.PUT("/games", createGame)
	router.PUT("/games/:rows/:cols", createGame)
	router.POST("/games/:gameid/join", joinGame) // API says PUT... zuch.
	router.GET("/games/:gameid", showGame)
	router.GET("/games/:gameid/:boardid", proxyHandler)
	router.GET("/games/:gameid/:boardid/:playerid", showPlayer)
	router.POST("/games/:gameid/move/:playerid/:direction", movePlayer)
	router.GET("/debug/profiledump", profileDump)

	return router
}

func showIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	log.Println("Go battlecamp!")
	w.Write([]byte("Go battlecamp!"))
}

func proxyHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

	if ps.ByName("gameid") == "asciiboard" {
		showAsciiBoard(w, r, ps)
	} else if ps.ByName("gameid") == "board" {
		showBoard(w, r, ps)
	} else if ps.ByName("boardid") == "join" {
		joinGame(w, r, ps)
	} else {
		listPlayers(w, r, ps)
	}
}

func listGames(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	e := json.NewEncoder(w)
	e.Encode(gameServer.ListGames())
}

func createGame(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	xString := ps.ByName("cols")
	yString := ps.ByName("rows")
	var game *game.Game

	log.Println("Creating new game...")

	if xString != "" && yString != "" {
		x, _ := strconv.Atoi(xString)
		y, _ := strconv.Atoi(yString)
		game = gameServer.AddGame(x, y)
	} else {
		game = gameServer.AddGame(56, 35)
	}

	w.WriteHeader(http.StatusCreated)
	e := json.NewEncoder(w)
	e.Encode(game)
	log.Printf("Created game %v", game.Id)
}

func joinGame(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	gameId, _ := strconv.ParseInt(ps.ByName("gameid"), 10, 64)
	d := json.NewDecoder(r.Body)
	var p player.Player
	d.Decode(&p)

	game := gameServer.GetGame(gameId)
	game.Join(&p)

	e := json.NewEncoder(w)
	e.Encode(&p)

	stomp.SendJson("update", p)

	log.Printf("Player %v joined game %v", p.Id, game.Id)
}

func showGame(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	id, _ := strconv.ParseInt(ps.ByName("gameid"), 10, 64)
	e := json.NewEncoder(w)
	e.Encode(gameServer.GetGame(id))
}

func listPlayers(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	gameId, _ := strconv.ParseInt(ps.ByName("gameid"), 10, 64)
	e := json.NewEncoder(w)
	e.Encode(gameServer.GetGame(gameId).Players)
}

func showPlayer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	gameId, _ := strconv.ParseInt(ps.ByName("gameid"), 10, 64)
	playerId := ps.ByName("playerid")
	g := gameServer.GetGame(gameId)
	p := g.GetPlayer(playerId)
	e := json.NewEncoder(w)
	e.Encode(p)
}

func movePlayer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	idString := ps.ByName("gameid")
	gameId, _ := strconv.ParseInt(idString, 10, 64)
	playerId := ps.ByName("playerid")
	g := gameServer.GetGame(gameId)
	p := g.GetPlayer(playerId)
	w.Header().Set("Content-Type", "application/json")
	direction := ps.ByName("direction")

	result := g.Move(p, direction)

	if !result {
		http.Error(w, "Bad request", http.StatusBadRequest)
	}

	e := json.NewEncoder(w)
	e.Encode(p.Pos)
	log.Printf("Player %v moved in direction %v\n", p.Id, direction)
}

// Request params: x={x}&y={y}&rows={rows}&cols={cols}
func showBoard(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	xString := req.FormValue("x")
	yString := req.FormValue("y")
	colsString := req.FormValue("cols")
	rowsString := req.FormValue("rows")

	id, _ := strconv.ParseInt(ps.ByName("boardid"), 10, 64)
	b := gameServer.GetGame(id).Board

	if xString != "" && yString != "" && colsString != "" && rowsString != "" {
		x, _ := strconv.Atoi(xString)
		y, _ := strconv.Atoi(yString)
		cols, _ := strconv.Atoi(colsString)
		rows, _ := strconv.Atoi(rowsString)
		b.WriteJSON(w, x, y, cols, rows)
	} else if xString != "" || yString != "" || colsString != "" || rowsString != "" {
		http.Error(w, "Bad request", http.StatusBadRequest)
	} else {
		b.WriteJSON(w, 0, 0, b.Width, b.Height)
	}
}

func showAsciiBoard(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "text/plain;charset=utf-8")

	id, _ := strconv.ParseInt(ps.ByName("boardid"), 10, 64)
	b := gameServer.GetGame(id).Board.String()
	w.Write([]byte(b))
}

func profileDump(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	pprof.StopCPUProfile()
}
