package server

import (
	"log"
	"math"
	"testing"

	v "hackerbots.us/vector"
)

func init() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

func TestCollision(t *testing.T) {
	tests := []struct {
		g         Game
		r         Robot
		target    v.Vector2d
		location  *v.Point2d
		collision bool
	}{
		// should intersect with first box
		{
			g: Game{
				width:  800,
				height: 400,
				obstacles: []Obstacle{
					Obstacle{
						Bounds: v.AABB2d{
							A: v.Point2d{X: 200, Y: 100},
							B: v.Point2d{X: 300, Y: 200},
						},
					},
					Obstacle{
						Bounds: v.AABB2d{
							A: v.Point2d{X: 400, Y: 200},
							B: v.Point2d{X: 600, Y: 300},
						},
					},
				},
			},
			r: Robot{
				Position: v.Point2d{X: 100, Y: 100},
				// Heading:  v.Vector2d{1, 1},
			},
			target:    v.Vector2d{X: 900, Y: 350},
			location:  &v.Point2d{X: 200, Y: 138.88889},
			collision: true,
		},
		// shouldn't intersect at all
		{
			g: Game{
				width:  800,
				height: 400,
				obstacles: []Obstacle{
					Obstacle{
						Bounds: v.AABB2d{
							A: v.Point2d{X: 200, Y: 100},
							B: v.Point2d{X: 300, Y: 200},
						},
					},
				},
			},
			r: Robot{
				Position: v.Point2d{X: 100, Y: 100},
			},
			target:    v.Vector2d{X: 0, Y: 0},
			collision: false,
		},
	}
	for _, test := range tests {
		collision, location, _ := test.r.checkCollisions(&test.g, test.target)
		if collision != test.collision {
			t.Errorf("expected: %t, actual: %t", test.collision, collision)
		}
		if test.location == nil {
			if location != nil {
				t.Errorf("expected: %+v, actual: %+v", test.location, location)
			}
		}
		if test.location != nil {
			if location == nil {
				t.Errorf("expected: %+v, actual: %+v", test.location, location)
			} else {
				if math.Abs(float64(location.X-test.location.X)) > 1e-4 || math.Abs(float64(location.Y-test.location.Y)) > 1e-4 {
					t.Errorf("expected: %+v, actual: %+v", test.location, location)
				}
			}
		}
	}
}

// XXX
func TestBotBotCollisions(t *testing.T) {
	t.Skip("NYI")
}

func TestProbeResultType(t *testing.T) {
	g := Game{
		width:  800,
		height: 400,
		obstacles: []Obstacle{
			Obstacle{
				Bounds: v.AABB2d{
					A: v.Point2d{X: 200, Y: 100},
					B: v.Point2d{X: 300, Y: 200},
				},
			},
			Obstacle{
				Bounds: v.AABB2d{
					A: v.Point2d{X: 400, Y: 200},
					B: v.Point2d{X: 600, Y: 300},
				},
			},
		},
		players: make(map[*Player]bool),
	}

	r1 := Robot{
		Position: v.Point2d{X: 100, Y: 100},
		Probe:    &v.Point2d{X: 900, Y: 350},
		Id:       "Bilbo's Bot",
	}
	p1 := Player{
		Robots: []*Robot{&r1},
		ProtoTalker: ProtoTalker{
			Id: "bilbo",
		},
	}

	r2 := Robot{
		Position: v.Point2d{X: 100, Y: 200},
		Probe:    &v.Point2d{X: 100, Y: 90},
		Id:       "Frodo's Bot",
	}
	p2 := Player{
		Robots: []*Robot{&r2},
		ProtoTalker: ProtoTalker{
			Id: "Frodo",
		},
	}

	g.players[&p1] = true
	g.players[&p2] = true

	r1.Tick(&g)
	r2.Tick(&g)

	if r1.ProbeResult.Type != "obstacle" {
		t.Errorf("incorrect probe type (expected obstacle, got %s)", r1.ProbeResult.Type)
	}
	if r2.ProbeResult.Type != "robot" {
		t.Errorf("incorrect probe type (expected robot, got %s)", r1.ProbeResult.Type)
	}
}
