using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Valg.EVA.Skanning.Repositories.ElectionConfig;
using Valg.EVA.Skanning.ServicesModel.Internal;
using Valg.EVA.Skanning.ServicesModel.ElectionConfig.Model;

namespace Valg.EVA.Skanning.ServicesModel.ElectionConfig.DataProvider
{
    public class MunicipalityDataProvider : IMunicipalityDataProvider
    {
        private readonly IMunicipalitiesCsvReader reader;
        private readonly IMunicipalityRepository repository;
        private readonly ConcurrentDictionary<string, IDictionary<string, County>> counties;
        private readonly ConcurrentDictionary<string, IDictionary<string, Municipality>> municipalities;
        private readonly ConcurrentDictionary<string, string> csvContent;

        public MunicipalityDataProvider(IMunicipalitiesCsvReader reader, IMunicipalityRepository repository)
        {
            this.reader = reader;
            this.repository = repository;
            csvContent = new ConcurrentDictionary<string, string>();
            counties = new ConcurrentDictionary<string, IDictionary<string, County>>();
            municipalities = new ConcurrentDictionary<string, IDictionary<string, Municipality>>();
        }

        public County GetCounty(string electionEventId, string code)
        {
            if (electionEventId.IsStringActuallyLongOrInt() && code.IsStringActuallyLongOrInt())
            {
                var countiesAdded = counties.GetOrAdd(electionEventId, LoadCounties);
                if (countiesAdded.ContainsKey(code))
                {
                    return countiesAdded[code];
                }
            }

            return null;
        }


        public List<County> GetAllCounties(string electionEventId)
        {
            if (electionEventId.IsStringActuallyLongOrInt())
            {
                var countiesAdded = counties.GetOrAdd(electionEventId, LoadCounties);
                return countiesAdded.Values.ToList();
            }

            return null;
        }

        public Municipality GetMunicipality(string electionEventId, string code)
        {
            if (electionEventId.IsStringActuallyLongOrInt() && code.IsStringActuallyLongOrInt())
            {
                var municipalitiesAdded = municipalities.GetOrAdd(electionEventId, LoadMunicipalities);
                if (municipalitiesAdded.ContainsKey(code))
                {
                    return municipalitiesAdded[code];
                }
            }

            return null;
        }

        public string GetAreaName(string electionEventId, string code)
        {
            var parts = code.Split('.');
            if (parts.Count() == 2)
            {
                return GetCounty(electionEventId, parts[1]).Name;
            }
            if (parts.Count() == 3)
            {
                return GetMunicipality(electionEventId, parts[2]).Name;
            }

            return null;
        }

        public List<Municipality> GetMunicipalitiesInCounty(string electionEventId, string countyCode)
        {
            List<Municipality> municipalitiesInCounty = new List<Municipality>();
            if (electionEventId.IsStringActuallyLongOrInt() && countyCode.IsStringActuallyLongOrInt())
            {
                var municipalitiesAdded = municipalities.GetOrAdd(electionEventId, LoadMunicipalities);
                municipalitiesInCounty.AddRange(municipalitiesAdded.Values.Where(p => p.CountyCode == countyCode));
            }

            return municipalitiesInCounty;
        }

        public void PreLoadCache(string electionEventId)
        {
            csvContent.GetOrAdd(electionEventId, LoadData);
        }

        

        private IDictionary<string, County> LoadCounties(string electionEventId)
        {
            return reader
                .ReadCounties(GetCsvContent(electionEventId))
                .ToDictionary(c => c.Code);
        }

        private IDictionary<string, Municipality> LoadMunicipalities(string electionEventId)
        {
            return reader
                .ReadMunicipalities(GetCsvContent(electionEventId))
                .ToDictionary(m => m.Code);
        }

        private string GetCsvContent(string electionEventId)
        {
            return csvContent.GetOrAdd(electionEventId, LoadData);
        }

        private string LoadData(string electionEventId)
        {
            return repository.GetMunicipalities(electionEventId);
        }
    }
}
