﻿using System;
using UnityEditor;
using UnityEngine;
using Gamelogic.Grids;

public class Grid : GLMonoBehaviour 
{
	private readonly Rect centerRect = new Rect(0, 0, 0, 0);

	[Serializable]
	public enum Shape
	{
		Rectangle,
		Parallelogram,
		FatRectangle,
		ThinRectangle,
	}

	[Serializable]
	public enum Plane
	{
		XY,
		XZ
	}

	public enum Alignment
	{
		TopLeft,
		TopCenter,
		TopRight,
		MiddleLeft,
		MiddleCenter,
		MiddleRight,
		BottomLeft,
		BottomCenter,
		BottomRight
	}

	//[SerializeField] 
	public Cell cellPrefab;

	//[SerializeField]
	public Shape shape;

	//[SerializeField]
	public InspectableVectorPoint dimensions = new InspectableVectorPoint();

	//[SerializeField]
	public Plane plane;

	//[SerializeField]
	public Alignment alignment = Alignment.MiddleCenter;

	//[SerializeField]
	public float cellSpacingFactor = 1;

	public int colorFuncX0 = 1;
	public int colorFuncX1 = 1;
	public int colorFuncY1 = 1;
	
	public Color[] colors = ExampleUtils.colors;

	[SerializeField]
	private PointyHexGrid<Cell> grid;

	[SerializeField]
	private IMap3D<PointyHexPoint> map;

	public PointyHexGrid<Cell> GridData
	{
		get
		{
			return grid;
		}
	}

	public VectorPoint Dimensions
	{
		get
		{
			return dimensions.GetVectorPoint();
		}
	}

	public void Awake()
	{
		InitGrid();
		InitMap();
		RelinkCells();
	}

	public void Update()
	{
		if (Input.GetMouseButtonDown(0))
		{
			Vector3 worldPosition = ExampleUtils.ScreenToWorld(gameObject, Input.mousePosition);

			PointyHexPoint point = map[worldPosition];

			if (grid.Contains(point))
			{
				SendMessage("OnCellClicked", point, SendMessageOptions.DontRequireReceiver);
				grid[point].SendMessage("OnCellClicked", SendMessageOptions.DontRequireReceiver);
			}
		}
	}

	[ContextMenu("Build Grid")]
	public void BuildGrid()
	{
		InitGrid();
		InitMap();
		SetupGrid();
	}

	private void InitGrid()
	{
		if (Application.isPlaying)
		{
			//transform.DestroyChildren();
		}
		else
		{
			transform.DestroyChildrenImmediate();
		}

		VectorPoint rectDimensions = Dimensions;

		switch (shape)
		{
			case Shape.Rectangle:
				grid = PointyHexGrid<Cell>.Rectangle(rectDimensions.X, rectDimensions.Y);
				break;
			case Shape.Parallelogram:
				grid = PointyHexGrid<Cell>.Parallelogram(rectDimensions.X, rectDimensions.Y);
				break;
			case Shape.FatRectangle:
				grid = PointyHexGrid<Cell>.ThinRectangle(rectDimensions.X, rectDimensions.Y);
				break;
			case Shape.ThinRectangle:
				grid = PointyHexGrid<Cell>.FatRectangle(rectDimensions.X, rectDimensions.Y);
				break;
			default:
				throw new ArgumentOutOfRangeException();
		}
	}

	private void SetupGrid()
	{
		foreach (var point in grid)
		{
			var cell = Instantiate(cellPrefab);
			cell.__grid = this;
			cell.transform.parent = transform;
			cell.transform.localScale = Vector2.one;
			cell.transform.localPosition = map[point];

			cell.TileType = point.GetColor(colorFuncX0, colorFuncX1, colorFuncY1);
			cell.GridPoint = point;
			grid[point] = cell;
		}
	}

	private void RelinkCells()
	{
		var cells = FindObjectsOfType<Cell>();

		var selectedObject = Selection.activeObject;

		foreach (var cell in cells)
		{
			grid[cell.GridPoint] = cell;
			cell.TileType = cell.TileType;
			cell.HighlightOn = cell.HighlightOn;
		}
	}

	private void InitMap()
	{
		Func<WindowedMap<PointyHexPoint>, IMap<PointyHexPoint>> alignmentFunc;
//
		var cellWidth = cellPrefab.Dimensions.x;
		var cellHeight = cellPrefab.Dimensions.x/69*80;
		var cellDimensions = new Vector2(cellWidth, cellHeight);

		var windowedHexMap = new PointyHexMap(cellDimensions*cellSpacingFactor)
			.WithWindow(centerRect);

		switch (alignment)
		{
			case Alignment.TopLeft:
				alignmentFunc = windowedMap => windowedMap.AlignTopLeft(grid);
				break;
			case Alignment.TopCenter:
				alignmentFunc = windowedMap => windowedMap.AlignTopCenter(grid);
				break;
			case Alignment.TopRight:
				alignmentFunc = windowedMap => windowedMap.AlignRight(grid);
				break;
			case Alignment.MiddleLeft:
				alignmentFunc = windowedMap => windowedMap.AlignMiddleLeft(grid);
				break;
			case Alignment.MiddleCenter:
				alignmentFunc = windowedMap => windowedMap.AlignMiddleCenter(grid);
				break;
			case Alignment.MiddleRight:
				alignmentFunc = windowedMap => windowedMap.AlignMiddleRight(grid);
				break;
			case Alignment.BottomLeft:
				alignmentFunc = windowedMap => windowedMap.AlignBottomLeft(grid);
				break;
			case Alignment.BottomCenter:
				alignmentFunc = windowedMap => windowedMap.AlignBottomCenter(grid);
				break;
			case Alignment.BottomRight:
				alignmentFunc = windowedMap => windowedMap.AlignBottomRight(grid);
				break;
			default:
				throw new ArgumentOutOfRangeException();
		}

		var hexMap = alignmentFunc(windowedHexMap);

		switch (plane)
		{
			case Plane.XY:
				map = hexMap.To3DXY();
				break;
			case Plane.XZ:
				map = hexMap.To3DXZ();
				break;
			default:
				throw new ArgumentOutOfRangeException();
		}
	}
}
