using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using Valg.EVA.Skanning.Entity.ReadModel;
using Valg.EVA.Skanning.Oasis.EMLStandard;
using Valg.EVA.Skanning.ServicesModel.ElectionConfig.Model;

namespace Valg.EVA.Skanning.ServicesModel.ElectionConfig.DataProvider
{
    public class ElectionConfigXmlDeserializationHelper : IElectionConfigXmlDeserializationHelper
    {
        private const string XmlNameSpace = "urn:oasis:names:tc:evs:schema:eml";

        public List<ElectionEvent> DeserializeElectionEvent(IEnumerable<XmlResult> xmlResults)
        {
            var xs = new XmlSerializer(typeof(EventIdentifierStructure));

            return xmlResults
               .Select(eId => (EventIdentifierStructure)xs.Deserialize(new StringReader(eId.XmlContent)))
               .Select(eIds => new ElectionEvent(eIds.Id, eIds.EventName))
               .ToList();
        }

        public List<Contest> DeserializeContests(IEnumerable<XmlResult> xmlResults)
        {
            var xs = new XmlSerializer(typeof(ContestIdentifierStructure));
            return xmlResults
            .Select(cId => (ContestIdentifierStructure)xs.Deserialize(new StringReader(cId.XmlContent)))
                .Select(cIdS => new Contest(cIdS.Id, cIdS.ContestName))
                .ToList();
        }

        public List<Election> DeserializeElections(IEnumerable<XmlResult> xmlResults)
        {
            var xRoot = new XmlRootAttribute { ElementName = "ElectionIdentifier", Namespace = XmlNameSpace, IsNullable = true };
            var xs = new XmlSerializer(typeof(ElectionIdentifierStructure), xRoot);
            return xmlResults.Select(election => (ElectionIdentifierStructure)xs.Deserialize(new StringReader(election.XmlContent)))
                .Select(electionDeserialized => new Election(
                    electionDeserialized.Id,
                    electionDeserialized.ElectionName,
                    electionDeserialized.ElectionCategory,
                    electionDeserialized.ElectionGroup.Id,
                    electionDeserialized.ElectionGroup.Value))
                .ToList();
        }

        public Election DeserializeElection(IEnumerable<XmlResult> xmlResults)
        {
            return DeserializeElections(xmlResults).Single();
        }
        
        public CountMetricsForContest DeserializeCountMetricsForContests(IEnumerable<XmlResult> xmlResults, string contestId)
        {
            var xRoot = new XmlRootAttribute { ElementName = "CountMetric", Namespace = XmlNameSpace, IsNullable = true };
            var xs = new XmlSerializer(typeof(CountMetricStructure), xRoot);
            var allMetrics = xmlResults.Select(xmlFragment => (CountMetricStructure)xs.Deserialize(new StringReader(xmlFragment.XmlContent))).ToList();
            var metric = new CountMetricsForContest(contestId,
                hasPersonalVotes: allMetrics.Any(s => s.Type == "personal") ? allMetrics.Single(s => s.Type == "personal").Value > 0 : (bool?)null,
                hasRenumbering: allMetrics.Any(s => s.Type == "renumber") ? allMetrics.Single(s => s.Type == "renumber").Value > 0 : (bool?)null,
                hasWriteIns: allMetrics.Any(s => s.Type == "writein") ? allMetrics.Single(s => s.Type == "writein").Value > 0 : (bool?)null,
                hasStrikeouts: allMetrics.Any(s => s.Type == "strikeout") ? allMetrics.Single(s => s.Type == "strikeout").Value > 0 : (bool?)null
                );
            return metric;
        }

        public List<ReportingUnit> DeserializeReportingUnits(IEnumerable<XmlResult> xmlResults)
        {
            var xRoot = new XmlRootAttribute { ElementName = "ReportingUnitIdentifier", Namespace = XmlNameSpace, IsNullable = true };
            var xs = new XmlSerializer(typeof(ReportingUnitIdentifierStructure), xRoot);
            return xmlResults.Select(ru => (ReportingUnitIdentifierStructure)xs.Deserialize(new StringReader(ru.XmlContent)))
              .Select(ruS => new ReportingUnit(ruS.Id, ruS.Value))
              .ToList();
        }

        public List<PollingDistrict> DeserializePollingDistricts(IEnumerable<XmlResult> xmlResults)
        {
            var xs = new XmlSerializer(typeof(AreaStructure));
            return xmlResults.Select(pollingDistrict => (AreaStructure)xs.Deserialize(new StringReader(pollingDistrict.XmlContent)))
               .Select(pollingDistrictDeserialized => new PollingDistrict { Id = pollingDistrictDeserialized.Id, Name = pollingDistrictDeserialized.Value })
               .ToList();
        }

        public List<VotingCategory> DeserializeVotingCategories(IEnumerable<XmlResult> xmlResults)
        {
            var xRoot = new XmlRootAttribute { ElementName = "ResultsReported", Namespace = XmlNameSpace, IsNullable = true };
            var xs = new XmlSerializer(typeof(ResultsReportedStructure), xRoot);
            return xmlResults
               .Select(rr => (ResultsReportedStructure)xs.Deserialize(new StringReader(rr.XmlContent)))
               .Select(rrs => new VotingCategory(rrs.Status.ChannelID, rrs.Status.Type, rrs.Status.Notes))
               .ToList();
        }

        public int? DeserializeMaxWriteIn(XmlResult xmlResults)
        {
            if (xmlResults != null)
            {
                int maxWriteIn;
                using (XmlReader reader = XmlReader.Create(new StringReader(xmlResults.XmlContent)))
                {
                    reader.MoveToContent();
                    maxWriteIn = reader.ReadElementContentAsInt();
                }
                return maxWriteIn;
            }
            else
            {
                return null;
            }
        }
    }
}
