using System.Collections;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;

public class MouseDragAndAttach : MonoBehaviour {
    
    World world;
    public float reach = 10f;
    public float snapDistance = 1.5f;
    bool isAttachedToMouse;
    static Plane plane = new Plane(Vector3.up, Vector3.zero);

    public enum ConnectionFailedReason { distance, overlap };
    public delegate void connectionFailedDelegate(ConnectionFailedReason reason);
    public static event connectionFailedDelegate OnFailedConnect;

	void Start () {
        world = GetComponent<World>();
        isAttachedToMouse = false;
	}

    public void OnTileClick()
    {
        if (!world.tiles.Any(t => Vector3.SqrMagnitude(t.transform.position - Game.player.transform.position) < reach * reach))
            return; // too far away
        isAttachedToMouse = true;
    }

    public void onTileRelease()
    {
        isAttachedToMouse = false;
        if (!world.tiles.Any(
                t => Game.player.tiles.Any(
                    u => Vector3.SqrMagnitude(t.transform.position - u.transform.position) < snapDistance * snapDistance)))
            return;

        AttachToPlayer();
    }

	void Update () {
        if (!isAttachedToMouse)
            return;
        var mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
        float distance = 0;
        if (!plane.Raycast(mouseRay, out distance))
            return;
        transform.position = mouseRay.GetPoint(distance);
	}

    void AttachToPlayer()
    {
        if (Game.player.tiles.Count() + world.tiles.Count() > Game.zone.allowedTiles)
        {
            transform.SetParent(null);
            Game.hints.ShowError("You can only carry so much.\nRight click may ease your burden, until you gain in strength.");
            return;
        }
        // try to snap to the nearest 60 degree angle
        transform.SetParent(Game.player.transform);
        var rot = transform.localRotation.eulerAngles;
        rot.y = Mathf.Round(rot.y / 60) * 60;
        transform.localRotation = Quaternion.Euler(rot);
        int rotation = Mathf.RoundToInt(rot.y);

        // now check if the position is valid: no tiles can overlap, and at least one tile must be touching an existing one.
        var origin = HexGrid.Coordinates(new Vector2(transform.localPosition.x, transform.localPosition.z));
        var originPos = HexGrid.Position(origin);
        transform.localPosition = new Vector3(originPos.x, 0, originPos.y);
        var playerCoords = Game.player.tileCoords;
        var ourCoords = world.tileCoords.Select(t => HexGrid.Rotate(t, rotation) + origin).ToArray();

        if (HexGrid.Overlap(ourCoords, playerCoords))
        {
            // we can't place the world there. Inform the player
            transform.SetParent(null);
            OnFailedConnect(ConnectionFailedReason.overlap);
            return;
        }
        if (HexGrid.Distance(HexGrid.minDistancePair(ourCoords, playerCoords)) > 1)
        {
            transform.SetParent(null);
            OnFailedConnect(ConnectionFailedReason.distance);
            return;
        }

        // all went well, let's attach
        var ourTiles = world.tiles.ToArray();
        foreach (Tile tile in ourTiles)
        {
            world.grid.Remove(tile);
            tile.transform.SetParent(Game.player.transform);
            Game.player.grid.Add(tile);
            tile.isPlayerTile = true;
        }
        Destroy(this);

    }
}
