using System;
using System.Collections.Generic;
using Assets.Voronoi;
using Random = System.Random;

namespace Assets.Map
{
    public class LocationGenerator
    {
        private readonly Graph<LocationSite> _sites;
        private readonly Graph<Location> _locations;
        
        private readonly List<(int, Location)> _queue = new List<(int, Location)>();
        
        private readonly Random _random;
        
        public Graph<LocationSite> Sites => _sites;
        public Graph<Location> Result => _locations;
        
        public bool Done => _queue.Count == 0;

        public LocationGenerator(List<Location> locations, Graph<Site> sites, Random random = null)
        {
            _sites     = sites.Morph(s => new LocationSite(s));
            _locations = new Graph<Location> { Vertices = new List<Location>(locations) };
            
            _random = random ?? new Random();
        }

        public void SetLocation(int vertex, Location location)
        {
            location.AddSite(_sites.Vertices[vertex]);

            foreach (var neighbour in _sites.Neighbours(vertex))
                if (_sites.Vertices[neighbour].Location == null)
                    _queue.Add((neighbour, location));
                else if (location != _sites.Vertices[neighbour].Location)
                    _locations.AddEdge(
                        _locations.Vertices.IndexOf(location),
                        _locations.Vertices.IndexOf(_sites.Vertices[neighbour].Location)
                    );
        }

        private (int, Location) Dequeue()
        {
            while (_queue.Count > 0)
            {
                var index = _random.Next(_queue.Count);
                var pair  = _queue[index];

                _queue.RemoveAt(index);

                if (_sites.Vertices[pair.Item1].Location == null) return pair;
            }
            
            throw new Exception("No more elements.");
        }
        
        public void Step()
        {
            try
            {
                var (vertex, location) = Dequeue();

                SetLocation(vertex, location);
            }
            catch (Exception ex)
            {
            }
        }
    }
}