using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models.Game;
using Models.Interfaces;

namespace Models.Rules
{ 
    /// <summary>
    /// The Rules class contains all the rules of the game. It is used to check if a move is valid or not.
    /// </summary>
    public class Rules : IRules
    {

        public bool IsCellEmpty(Cell playerChoice)
        {
            if (playerChoice == null || playerChoice.Value == null) return true;
            return false;
        }

        public bool IsCellValid(Cell playerChoicePosition, List<Cell> cells)
        {
            if (!IsCellEmpty(playerChoicePosition)) return false;

            if (EveryAdjacentCells(playerChoicePosition, cells).Count == 1) return false;

            return true;
        }

        //public bool IsCellAdjacent(Cell choosenCell, Cell targetCell)
        //{
        //    if (Math.Abs(choosenCell.X - targetCell.X) > 1 || Math.Abs(choosenCell.Y - targetCell.Y) > 1)
        //        return false;
        //    if (Math.Abs(choosenCell.X - targetCell.X) > 1 && Math.Abs(choosenCell.Y - targetCell.Y) > 1)
        //        return false;
        //    if (choosenCell.X == 0 && targetCell.X == 4)
        //        return false;
        //    if (choosenCell.Y == 0 && targetCell.Y == 4)
        //        return false;
        //    if (choosenCell.X == 4 && targetCell.X == 0)
        //        return false;
        //    if (choosenCell.Y == 4 && targetCell.Y == 0)
        //        return false;
        //    if (choosenCell.X == targetCell.X && choosenCell.Y == targetCell.Y)
        //        return false;

        //    return true;
        //}    

        public bool IsCellAdjacent(Cell choosenCell, Cell targetCell)
        {
            if (Math.Abs(choosenCell.X - targetCell.X) <= 1 && Math.Abs(choosenCell.Y - targetCell.Y) <= 1)
            {
                if (choosenCell.X != targetCell.X || choosenCell.Y != targetCell.Y)
                {
                    return true;
                }
            }

            return false;
        }


        public bool IsInRopePaths (Cell adjacente,List<List<Cell>> ropePaths,int index)
        {
            foreach (List<Cell> path in ropePaths)
            {
                if (path.Contains(adjacente))
                {
                    index=ropePaths.IndexOf(path);
                    return true;
                }
            }
            return false;
        }

        public bool AsValue (Cell choosenCell, List<List<Cell>> ropePaths,int index)
        {
            foreach (var item in ropePaths[index])
            {
                if (choosenCell.Value == item.Value) return true;
            }
            return false;
        }
        //public bool NearCellIsValid(Cell choosenCell, List<Cell> cells)
        //{
        //    if (choosenCell == null || cells == null) return false;
            
        //    IEnumerable<Cell> PlayedCellsQuery =
        //        from cell in cells
        //        where cell.Value != null
        //        select cell;

        //    foreach (var cell in PlayedCellsQuery)
        //    {
        //        if(!IsCellAdjacent(choosenCell, cell)) continue;

        //        return true;
        //    }

        //    return false;
        //}

        public bool NearCellIsValid(Cell choosenCell, List<Cell> cells)
        {
            if (choosenCell == null || cells == null) return false;

            IEnumerable<Cell> PlayedCellsQuery =
                from cell in cells
                where cell.Value != null
                select cell;

            foreach (var cell in PlayedCellsQuery)
            {
                if (IsCellAdjacent(choosenCell, cell))
                {
                    return true;
                }
            }

            return false;
        }


        public void IsZoneValidAndAddToZones(Cell chosenCell, Map map)
        {
            if (chosenCell == null ||chosenCell.Value == null) return;

            List<Cell> adjacentCells = new List<Cell>();

            adjacentCells = EveryAdjacentCells(chosenCell, map.Boards.ToList());

            foreach(var cells in adjacentCells)
            {
                if (cells.Value == chosenCell.Value)
                {
                    if(IsValueInZones(cells, map.Zones))
                    {
                        AddToZone(chosenCell, map.Zones);
                    }
                    else
                    {
                        NewZoneIsCreated(chosenCell, cells, map);
                    }
                    //return true; // Il y a une cellule adjacente avec la même valeur donc une zone est créée si elle n'est pas déjà existante
                    // Si il return true, tout c'est bien passer
                }
            }

            return;
        }

        public bool IsValueInZones(Cell chosenCell, List<List<Cell>> zones)
        {
            if (chosenCell == null) return false;

            for (int i = 0; i < zones.Count; i++)
            {
                if (zones[i][0].Value == chosenCell.Value)
                {
                    return true;
                }
            }
            return false;
        }

        public bool IsCellInZone(Cell chosenCell, List<List<Cell>> zones)
        {
            if (chosenCell == null) return false;

            for (int i = 0; i < zones.Count; i++)
            {
                if (zones[i].Contains(chosenCell))
                {
                    return true;
                }
            }
            return false;
        }

        public void AddToZone(Cell chosenCell, List<List<Cell>> zones)
        {
            if (chosenCell == null || chosenCell.Value == null) return;

            if (IsCellInZone(chosenCell, zones)) return;

            for (int i = 0; i < zones.Count; i++)
            {
                if (zones[i][0].Value == chosenCell.Value)
                {
                    zones[i].Add(chosenCell);
                    return;
                }
            }
            return;
        }

        public void NewZoneIsCreated(Cell firstCell, Cell secondCell, Map map)
        {
            if (firstCell == null || secondCell == null || firstCell.Value == null || secondCell.Value == null) return;
            List<Cell> newZone = new List<Cell>();
            newZone.Add(firstCell);
            newZone.Add(secondCell);
            map.Zones.Add(newZone);
        }

        public List<Cell> EveryAdjacentCells(Cell choosenCell, List<Cell> cells)
        {
            List<Cell> adjacentCells = new List<Cell>();
            
            if (choosenCell == null || cells == null) return adjacentCells;

            foreach (var cell in cells)
            {
                if (choosenCell == cell) continue;
                if (IsCellAdjacent(choosenCell, cell))
                {
                    adjacentCells.Add(cell);
                }
            }

            return adjacentCells;
        }

        public int? FinalCalculusOfZones(List<List<Cell>> zones)
        {
            int? calculus = 0;
            for(int i = 0; i < zones.Count; i++)
            {
                calculus += zones[i].Count - 1 + zones[i][0].Value;
                if (zones[i].Count > 9)
                {
                    calculus += (zones[i].Count - 9) * 5 - (zones[i].Count - 9);
                }
            }
            return calculus;
        }

        public int? ScoreRopePaths(List<Cell> paths)
        {
            int? score = 0;
            IEnumerable<Cell> sortPaths =
                from cell in paths
                orderby cell.Value descending
                select cell;
            foreach (var item in sortPaths)
            {
                if (score == 0)
                    score += item.Value;
                else
                    score++;
            }
            return score;
        }

    }
}