using System.Collections.ObjectModel;
using System.Linq;
using Valg.EVA.Skanning.Contracts;
using Valg.EVA.Skanning.Contracts.CommonEnums;
using Valg.EVA.Skanning.Entity.SerializedEntities.CountResultModel;

namespace Valg.EVA.Skanning.Services.CountResult.XmlBuilders
{
    public abstract class EmlBaseBuilder
    {
        protected struct ElectionMetaData
        {
            public string EventIdentifier { get; set; }

            public string ElectionIdentifier { get; set; }

            public string ContestId { get; set; }

            public string ReportingUnitIdentifier { get; set; }

            public string VotingCategory { get; set; }

            public string AreaContextId { get; set; }

            public string ElectionGroup { get; set; }

            public CountingType CountingType { get; set; }
        }

        protected ElectionMetaData GetElectionMetaData(ReadOnlyCollection<CastVote> castVotes, string reportingUnitIdentifierOfCaller)
        {
            if (IsResultConsistent(castVotes, reportingUnitIdentifierOfCaller))
            {
                CastVote castVote = castVotes.First();
                return new ElectionMetaData
                {
                    EventIdentifier = castVote.ElectionEventId,
                    ElectionIdentifier = castVote.ElectionIdentifier,
                    ContestId = castVote.ContestId,
                    VotingCategory = castVote.VotingCategory,
                    ReportingUnitIdentifier = castVote.ReportingUnitIdentifier,
                    AreaContextId = castVote.AreaContextId,
                    ElectionGroup = castVote.ElectionGroup,
                    CountingType = castVote.CountingType
                };
            }
            else
            {
                throw new System.FormatException("Can not get consistent set of meta data for result");
            }
        }

        protected string GetSuspectRejectionReasonCode(ReadOnlyCollection<CastVote> castVotes)
        {
            var votingCategory = castVotes.First().VotingCategory;
            if (IsAdvancedVotes(votingCategory))
            {
                return CastVote.RejectionReasonCode.FA.ToString(); 
            }
            else
            {
                return CastVote.RejectionReasonCode.VA.ToString();
            }            
        }

        private bool IsAdvancedVotes(string votingCategory)
        {
            return votingCategory == VotingCategoryKeys.FO_Forhåndsstemmer || votingCategory == VotingCategoryKeys.FS_SentInnkomne;
        }

        private bool IsResultConsistent(ReadOnlyCollection<CastVote> castVotes, string reportingUnitIdentifier)
        {
            var castVote = castVotes.First();
            
            bool electionEventIdIsConsistent = castVotes.All(p => p.ElectionEventId == castVote.ElectionEventId);
            bool electionIdentifierIsConsistent = castVotes.All(p => p.ElectionIdentifier == castVote.ElectionIdentifier);
            bool contestIdIsConsistent = castVotes.All(p => p.ContestId == castVote.ContestId);
            bool votingCategoryIsConsistent = castVotes.All(p => p.VotingCategory == castVote.VotingCategory);
            bool reportingUnitConsistent = castVotes.All(p => p.ReportingUnitIdentifier == reportingUnitIdentifier);
            bool areaContextIdIsConsistent = castVotes.All(p => p.AreaContextId == castVote.AreaContextId);
            bool electionGroupIsConsistent = castVotes.All(p => p.ElectionGroup == castVote.ElectionGroup);
            bool countingTypeIsConsistent = castVotes.All(p => p.CountingType == castVote.CountingType);

            return electionEventIdIsConsistent &&
                electionIdentifierIsConsistent &&
                contestIdIsConsistent &&
                votingCategoryIsConsistent &&
                reportingUnitConsistent &&
                areaContextIdIsConsistent &&
                electionGroupIsConsistent &&
                countingTypeIsConsistent;
        }
    }
}
