using Microsoft.Xna.Framework;
using System;
using Sledgemapper.Shared.Entities;

namespace Sledgemapper
{
    public sealed class State
    {
        private static readonly State instance = new ();

        public Tile SelectedTile { get; set; }
        public Tile HoveredTile { get; set; }
        public Wall SelectedWall { get; set; }
        public Overlay SelectedOverlay { get; set; }
        public SnapPoint SelectedSnapPoint { get; set; }
        public Note SelectedNote { get; set; }
        public int TileSize { get; set; }
        public string CurrentTileId { get; set; }
        public string CurrentWallId { get; set; }
        public string CurrentOverlayId { get; set; }
        public SnapPoint LineStart { get; internal set; }
        public float LineWidth { get; internal set; }
        public Vector3 ViewportCenter { get; set; }
        public InsertMode InsertMode { get; set; }
        public bool ShowCellNumbers { get; set; }
        public string CampaignName { get; set; }
        public Guid CampaignId { get; internal set; }
        public string MapName { get; internal set; }
        public Guid MapId { get; internal set; }

        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static State()
        {
        }

        private State()
        {
            CurrentTileId = "";
            CurrentWallId = "";
            CurrentOverlayId = "";
            SelectedTile = new() { X = 1, Y = 1 };
            HoveredTile = new() { X = 1, Y = 1 };
            SelectedWall = new() { X = 1, Y = 1 };
            SelectedOverlay = new() { X = 1, Y = 1 };
            SelectedNote = new() { X = 1, Y = 1 };
            TileSize = 30;
            LineWidth = 1;
            ViewportCenter = new(0, 0, 0);
        }

        public static State Instance
        {
            get
            {
                return instance;
            }
        }

        public Guid SessionId { get; internal set; }

        public void SelectClosestWall(Point mousePosition)
        {
            var topLeft = new Point(HoveredTile.X * TileSize, HoveredTile.Y * TileSize);
            var bottomLeft = new Point(HoveredTile.X * TileSize, HoveredTile.Y * TileSize + TileSize);
            var topRight = new Point(HoveredTile.X * TileSize + TileSize, HoveredTile.Y * TileSize);
            var bottomRight = new Point(HoveredTile.X * TileSize + TileSize, HoveredTile.Y * TileSize + TileSize);
            var center = new Point(HoveredTile.X * TileSize + TileSize / 2, HoveredTile.Y * TileSize + TileSize / 2);

            if (Utils.PointInTri(mousePosition, topLeft, center, bottomLeft)) //left wall
            {
                SelectedWall.X = HoveredTile.X;
                SelectedWall.Y = HoveredTile.Y;
                SelectedWall.Rotation = 1;
            }
            else if (Utils.PointInTri(mousePosition, topRight, bottomRight, center)) //right wall
            {
                SelectedWall.X = HoveredTile.X + 1;
                SelectedWall.Y = HoveredTile.Y;
                SelectedWall.Rotation = 1;
            }
            else if (Utils.PointInTri(mousePosition, topLeft, topRight, center)) //top wall
            {
                SelectedWall.X = HoveredTile.X;
                SelectedWall.Y = HoveredTile.Y;
                SelectedWall.Rotation = 0;
            }
            else if (Utils.PointInTri(mousePosition, bottomLeft, center, bottomRight))  //bottom wall
            {
                SelectedWall.X = HoveredTile.X;
                SelectedWall.Y = HoveredTile.Y + 1;
                SelectedWall.Rotation = 0;
            }
        }

        public bool CheckDistance(Point p1, Point p2, float d)
        {
            return ((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y)) < d * d;
        }

        public void SelectClosestSnapPoint(Point mousePosition)
        {
            var distance = TileSize / 4;

            if (CheckDistance(mousePosition, new Point(HoveredTile.X * TileSize, HoveredTile.Y * TileSize), distance)) //x y
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X, Y = HoveredTile.Y, Index = 1 };
            }
            else if (CheckDistance(mousePosition, new Point(HoveredTile.X * TileSize + TileSize / 2, HoveredTile.Y * TileSize + TileSize / 2), distance)) // x+1/2, y+1/2
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X, Y = HoveredTile.Y, Index = 4 }; 
            }
            else if (CheckDistance(mousePosition, new Point((HoveredTile.X + 1) * TileSize, HoveredTile.Y * TileSize), distance)) //x+1,y
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X + 1, Y = HoveredTile.Y, Index = 1 };
            }
            else if (CheckDistance(mousePosition, new Point((HoveredTile.X + 1) * TileSize, (HoveredTile.Y + 1) * TileSize), distance)) //x+1, y+1
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X + 1, Y = HoveredTile.Y + 1, Index = 1 };
            }
            else if (CheckDistance(mousePosition, new Point((HoveredTile.X) * TileSize, (HoveredTile.Y + 1) * TileSize), distance))//x,y+1
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X, Y = HoveredTile.Y + 1, Index = 1 };
            }
            else if (CheckDistance(mousePosition, new Point(HoveredTile.X * TileSize, HoveredTile.Y * TileSize + TileSize / 2), distance)) //x, x+1/2
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X, Y = HoveredTile.Y, Index = 3 };
            }
            else if (CheckDistance(mousePosition, new Point(HoveredTile.X * TileSize + TileSize / 2, HoveredTile.Y * TileSize ), distance)) // x+1/2,y
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X, Y = HoveredTile.Y, Index = 2 };
            }
             else if (CheckDistance(mousePosition, new Point(HoveredTile.X * TileSize + TileSize, HoveredTile.Y * TileSize + TileSize / 2), distance)) // x+1/2, y+1/2
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X+1, Y = HoveredTile.Y, Index = 3 }; 
            }
             else if (CheckDistance(mousePosition, new Point(HoveredTile.X * TileSize + TileSize / 2, HoveredTile.Y * TileSize + TileSize ), distance)) // x+1/2, y+1/2
            {
                SelectedSnapPoint = new SnapPoint { X = HoveredTile.X, Y = HoveredTile.Y+1, Index = 2 }; 
            }
        }

        public void SelectOverlay(Point mousePosition)
        {
            SelectedOverlay.X = HoveredTile.X;
            SelectedOverlay.Y = HoveredTile.Y;
            var q1 = Math.Pow(mousePosition.X - HoveredTile.X * TileSize, 2);
            var q2 = Math.Pow(HoveredTile.Y * TileSize - mousePosition.Y, 2);
            var s = Math.Sqrt(q1 + q2);

            if (s < TileSize / 3)
            {
                SelectedOverlay.Intersection = true;
                return;
            }

            q1 = Math.Pow(mousePosition.X - (HoveredTile.X + 1) * TileSize, 2);
            s = Math.Sqrt(q1 + q2);
            if (s < TileSize / 3)
            {
                SelectedOverlay.X = SelectedOverlay.X + 1;
                SelectedOverlay.Intersection = true;
                return;
            }

            //q1 = System.Math.Pow(mousePosition.X - (_hoveredTile.X + 1) * _tileSize, 2);
            q2 = Math.Pow((HoveredTile.Y + 1) * TileSize - mousePosition.Y, 2);
            s = Math.Sqrt(q1 + q2);
            if (s < TileSize / 3)
            {
                SelectedOverlay.X = SelectedOverlay.X + 1;
                SelectedOverlay.Y = SelectedOverlay.Y + 1;
                SelectedOverlay.Intersection = true;
                return;
            }

            q1 = Math.Pow(mousePosition.X - HoveredTile.X * TileSize, 2);
            q2 = Math.Pow((HoveredTile.Y + 1) * TileSize - mousePosition.Y, 2);
            s = Math.Sqrt(q1 + q2);
            if (s < TileSize / 3)
            {
                SelectedOverlay.X = SelectedOverlay.X;
                SelectedOverlay.Y = SelectedOverlay.Y + 1;
                SelectedOverlay.Intersection = true;
                return;
            }

            SelectedOverlay.Intersection = false;
        }
    }
}
