using CzokoŚmieciarka.MonoGameView.DataModels.Enums;
using CzokoŚmieciarka.MonoGameView.DataModels.Interfaces;
using CzokoŚmieciarka.MonoGameView.DataModels.Interfaces.GarbageCollector;
using CzokoŚmieciarka.MonoGameView.DataModels.Interfaces.TrashCans;
using CzokoŚmieciarka.MonoGameView.DataModels.Models;
using CzokoŚmieciarka.MonoGameView.DataModels.Models.Steps;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework.Content;
using System.Threading;

namespace CzokoŚmieciarka.MonoGameView.Algorithms
{
    public class DFS
    {
        public GarbageCollector Collector { get; set; }
        public ICloneable[,] Grid { get; set; }
        public DFS(GarbageCollector collector, ICloneable[,] grid)
        {
            this.Collector = collector;
            this.Grid = grid;
        }
        int count = 0;
        public List<Coords> Houses { get; set; }

        public List<IStep> BestPath(ContentManager content, GarbageCollector collector, ICloneable[,] grid)
        {
            Houses = new List<Coords>();
            for (int x = 0; x < grid.GetLength(0); x++)
            {
                for (int y = 0; y < grid.GetLength(1); y++)
                {
                    if (grid[x, y] is House)
                    {
                         Houses.Add(new Coords(x,y));
                        
                    }
                }
            }
                


            var r=Search(content, collector, grid, 0).Key;
            Console.WriteLine($"Counts : {count}");
            if (r == null) return new List<IStep>();
            return r;
            
        }

        List<IStep> PossibleSteps(AGarbageCollector collector, ICloneable[,] grid)
        {


            var result = new List<IStep>();

            if (!(collector.TrashContainers.Any(x => x.FillPercent > 0) && grid[collector.Coords.X,collector.Coords.Y] is ADump))
            {
                var moveSteps = new List<IStep>()
                {
                    new MoveStep(Direction.Up),
                    new MoveStep(Direction.Down),
                    new MoveStep(Direction.Left),
                    new MoveStep(Direction.Right)
                };
                var filteredMoveSteps = new List<IStep>();
                foreach (var item in moveSteps)
                {
                    var copyCollector = (AGarbageCollector)collector.Clone();
                    if (item.Invoke(copyCollector, grid))
                    {
                        var gcx = copyCollector.Coords.X;
                        var gcy = copyCollector.Coords.Y;
                        if (grid[gcx, gcy] is Road1 || grid[gcx, gcy] is House || (grid[gcx, gcy] is ADump && copyCollector.TrashContainers.Any(x => x.FillPercent > 0)))
                        {
                            result.Add(item);
                        }
                    }
                        
                    
                }


            }
            if (grid[collector.Coords.X, collector.Coords.Y] is House)
            {
                var collectSteps = new List<IStep>()
                {
                    new CollectStep(GarbageType.Glass),
                    new CollectStep(GarbageType.Organic),
                    new CollectStep(GarbageType.Paper),
                    new CollectStep(GarbageType.PlasticMetal)
                };
                foreach (var item in collectSteps)
                {
                    var copyCollector = (AGarbageCollector)collector.Clone();
                    var copyGrid = CopyGrid(grid);
                    if (item.Invoke(copyCollector, copyGrid))
                        result.Add(item);
                }
            }
            if (grid[collector.Coords.X, collector.Coords.Y] is ADump)
            {
                var collectSteps = new List<IStep>()
                {
                    new SpillStep(GarbageType.Glass),
                    new SpillStep(GarbageType.Organic),
                    new SpillStep(GarbageType.Paper),
                    new SpillStep(GarbageType.PlasticMetal)
                };
                foreach (var item in collectSteps)
                {
                    var copyCollector = (AGarbageCollector)collector.Clone();
                    var copyGrid = CopyGrid(grid);
                    if(item.Invoke(copyCollector, copyGrid))
                        result.Add(item);

                    
                }
            }
            return result;
        }

        KeyValuePair<List<IStep>, int> Search(ContentManager content, GarbageCollector collector, ICloneable[,] grid, int length)
        {

            //Thread.Sleep(1);
            this.Collector.Coords = collector.Coords;
            for (int x = 0; x < grid.GetLength(0); x++)
            {
                for (int y = 0; y < grid.GetLength(1); y++)
                {
                    this.Grid[x, y] = grid[x, y];
                }
            }

            Console.WriteLine(collector.HouseCounter);
            
            if (collector.Counter> 15 || length > 100)
                return new KeyValuePair<List<IStep>, int>(null,length);
            count++;
            if (Houses.All(c => (grid[c.X, c.Y] as IGarbageLocalization).TrashCans.All(j => j.FillPercent == 0.0))
               && 
               collector.TrashContainers.All(i => i.FillPercent == 0.0)
                )
                
            {
                return new KeyValuePair<List<IStep>, int>(new List<IStep>(), length);
            }
                var possibleSteps = PossibleSteps(collector, grid);
                                   
            foreach (var item in possibleSteps)
            {
                var copyCollector = (GarbageCollector)collector.Clone();
                var copyGrid = CopyGrid(grid);
               

                //if (copyGrid[copyCollector.Coords.X, copyCollector.Coords.Y] is IRoad1) copyGrid[copyCollector.Coords.X, copyCollector.Coords.Y] = new Road2();
                item.Invoke(copyCollector, copyGrid);
                var s = Search(content, copyCollector, copyGrid, length + 1);
                if (s.Key != null)
                {
                    s.Key.Insert(0, item);
                    return s;
                }
            }
            return new KeyValuePair<List<IStep>, int>(null, length);
            /*var min = int.MaxValue;
            var min_index = 0;
            for (int i = 0; i < mapped.Count; i++)
            {
                if (mapped.ElementAt(i).Value <= min)
                {
                    min = mapped.ElementAt(i).Value;
                    min_index = i;
                }
            }
            return mapped.ElementAt(min_index);
            */


        }






        

















        private ICloneable[,] CopyGrid(ICloneable[,] grid)
        {
            ICloneable[,] result = new ICloneable[grid.GetLength(0), grid.GetLength(1)];
            for (int x=0;x< grid.GetLength(0); x++)
            {
                for (int y=0;y< grid.GetLength(1); y++)
                {
                    result[x, y] = (ICloneable) grid[x, y].Clone();
                }
            }
            return result;
        }
    }
}