using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Cities;
using Assets.Common;

namespace Assets.AnnotationPass
{
    public class LocateCitiesPass : IAnnotationPass
    {
        public const string CitiesProperty = "Cities";
        public const string CityProperty = "City";
        
        private Graph<Location> _locationGraph;
        private Graph<MapSite> _basicGraph;
        private Random _random;

        public LocateCitiesPass(Random random = null)
        {
            _random = random ?? new Random();
        }

        IEnumerable<int> LocateCities()
        {
            return ChoosePoints(5);
        }

        City CreateCity(int vertex, int size)
        {
            City newCity = new City();
            
            var site = _basicGraph.Vertices[vertex];
            var sites = new List<MapSite> { site };
            var location = site.GetProperty<Location>(LandmassPass.SiteLocationProperty);
            
            for (int i = 0; i < size - 1; i++)
            {
                var neighbours = _basicGraph.Neighbours(site.Index)
                    .Select(j => _basicGraph.Vertices[j])
                    .Where(s => s.GetProperty<Location>(LandmassPass.SiteLocationProperty) == location && s.Tags.Contains(CommonTags.Empty))
                    .ToArray();

                if (neighbours.Length == 0) break;
                
                site = neighbours[_random.Next(neighbours.Length - 1)];
                sites.Add(site);
            }

            foreach (var s in sites.Distinct())
            {
                newCity.AddSite(s);
                s.SetProperty(CityProperty, newCity);
                s.Tags.Remove(CommonTags.Empty);
            }

            return newCity;
        }

        IEnumerable<int> ChoosePoints(int number)
        {
            var vertices = new List<int>();
            
            for (int i = 0; i < number; i++)
            {
                var randomLocation = _locationGraph.Vertices[_random.Next(1, _locationGraph.Vertices.Count())];
                var count = randomLocation.Sites.Count();
                var randomPoint = randomLocation.Sites[_random.Next(0, count)];
                vertices.Add(randomPoint.Index);
            }
            
            return vertices;
        }

        public void Annotate(Map map)
        {
            _basicGraph    = map.Sites.Clone() as Graph<MapSite>;
            _locationGraph = map.Metadata.GetProperty<Graph<Location>>(LandmassPass.MapLocationsProperty);

            var cities = new List<City>();
            var locations = LocateCities();
            
            foreach (var index in locations)
                cities.Add(CreateCity(index, _random.Next(0, 10)));
            
            map.Metadata.SetProperty(CitiesProperty, cities);
        }
    }
}