namespace Ato.CD.Inbound.CHTWTHHLD2018.Annual
{
    using System.Linq;
    using System.Collections.Generic;
    using VaTS;
    using DataContracts;
    using EN.IntegrationServices.CodeGenerationCHTWTHHLD;
    using EN.IntegrationServices.CodeGenerationCHTWTHHLDBEN;

    internal class CrossFormValidator
    {
        private CHTWTHHLD2018 Parent { get; }
        private IEnumerable<CHTWTHHLDBEN2018> Schedules { get; }
        private IEnumerable<CrossFormExtensions.Context> Contexts { get; }

        internal CrossFormValidator(BusinessDocument parent)
        {
            Parent = (CHTWTHHLD2018)parent.ConsumedReport;
            Schedules = (parent.ChildDocuments ?? new BusinessDocumentCollection()).Select(ben => (CHTWTHHLDBEN2018)ben.ConsumedReport);
            Contexts = BuildContexts();
        }

        public IEnumerable<ProcessMessageDocument> ValidateCrossFormRules()
        {
            var response = new List<ProcessMessageDocument>();

            VRATOCHTWTHHLD000011(response);
            VRATOCHTWTHHLDBEN000002(response);
            VRATOCHTWTHHLDBEN000200(response);
            VRATOCHTWTHHLDBEN000201(response);
            VRATOCHTWTHHLDBEN000040(response);
            VRATOCHTWTHHLD000018(response);
            VRATOCHTWTHHLD000017(response);
            VRATOCHTWTHHLD000061(response);

            return response;
        }

        #region VR.ATO.CHTWTHHLD.000017
        /*
        IF ([chtwthhld10] <> SUM(CHTWTHHLDBEN:Beneficiary:tns:IncomeTax.PayAsYouGoWithholding.TaxWithheld.Amount))
           RETURN VALIDATION MESSAGE
        ENDIF
        [chtwthhld10] = CHTWTHHLD:RP:rvctc2.02.12:IncomeTax.PayAsYouGoWithholding.TaxWithheld.Amount
        */
        private void VRATOCHTWTHHLD000017(List<ProcessMessageDocument> response)
        {
            bool assert = Parent.CHTWTHHLD10.HasValue && Parent.CHTWTHHLD10.Value != Schedules.Where(ben => ben.CHTWTHHLDBEN45.GetValueOrDefault() > 0).Sum(ben => ben.CHTWTHHLDBEN45);
            if (assert)
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CHTWTHHLD.000017",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "Total amount withheld is incorrect",
                    LongDescription = "Trust total amount withheld must be equal to the Total amount withheld from all the beneficiaries.",
                    Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.TaxWithheld.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CHTWTHHLD.000017" } }
                });
        }
        #endregion
        #region VR.ATO.CHTWTHHLD.000018
        /*
        IF ([chtwthhld9] <> SUM(CHTWTHHLDBEN:Beneficiary:rvctc2.xx.xx:IncomeTax.PayAsYouGoWithholding.PaymentGross.Amount))
           RETURN VALIDATION MESSAGE
        ENDIF
        [chtwthhld9] = CHTWTHHLD:RP:tns:IncomeTax.PayAsYouGoWithholding.PaymentGross.Amount
        */
        private void VRATOCHTWTHHLD000018(List<ProcessMessageDocument> response)
        {
            bool assert = Parent.CHTWTHHLD9.HasValue && Parent.CHTWTHHLD9.Value != Schedules.Where(ben => ben.CHTWTHHLDBEN46.GetValueOrDefault() > 0).Sum(ben => ben.CHTWTHHLDBEN46);
            if (assert)
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CHTWTHHLD.000018",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "Total amount of payments incorrect",
                    LongDescription = "Trust total amount of payments must be equal to the Total amount of payments from all the beneficiaries. ",
                    Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.PaymentGross.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CHTWTHHLD.000018" } }
                });
        }
        #endregion
        #region VR.ATO.CHTWTHHLD.000061
        /*
        IF COUNT(SCHEDULE(chtwthhldben)) > 50
           RETURN VALIDATION MESSAGE
        ENDIF
        */
        private void VRATOCHTWTHHLD000061(List<ProcessMessageDocument> response)
        {
            if (Schedules.Count() > 50)
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CHTWTHHLD.000061",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "Excessive number of beneficiaries attached",
                    LongDescription = "No more than 50 beneficiary's information must be attached for the Annual TFN withholding report.",
                    Location = "/xbrli:xbrl/xbrli:context",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CHTWTHHLD.000061" } }
                });
        }
        #endregion
        #region VR.ATO.CHTWTHHLD.000011
        //IF COUNT(SCHEDULE(chtwthhldben)) = 0
        //  RETURN VALIDATION MESSAGE
        private void VRATOCHTWTHHLD000011(List<ProcessMessageDocument> response)
        {
            if (!Schedules.Any())
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CHTWTHHLD.000011",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "No beneficiaries attached",
                    LongDescription = "At least one beneficiary's information must be attached.",
                    Location = "/xbrli:xbrl",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CHTWTHHLD.000011" } }
                });
        }
        #endregion
        #region VR.ATO.CHTWTHHLDBEN.000002
        //IF[chtwthhldben52] = chtwthhld:RP:entity.identifier.TFN
        //    RETURN VALIDATION MESSAGE
        //ENDIF
        //[chtwthhldben52] = CHTWTHHLDBEN:Beneficiary:tns:Identifiers.TaxFileNumber.Identifier
        private void VRATOCHTWTHHLDBEN000002(List<ProcessMessageDocument> response)
        {
            if (!string.IsNullOrWhiteSpace(Parent.RPIdentifierTFN))
                response.AddRange(Schedules.Where(ben => !string.IsNullOrWhiteSpace(ben.CHTWTHHLDBEN52) &&
                        ben.CHTWTHHLDBEN52.Equals(Parent.RPIdentifierTFN))
                        .Select(ben => new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.CHTWTHHLDBEN.000002",
                            Severity = ProcessMessageSeverity.Error,
                            Description = "Check Beneficiary tax file number",
                            LongDescription = "The Beneficiary tax file number should not be the same as the TFN of the trust.",
                            Location = $"/xbrli:xbrl/xbrli:context[{ben.BeneficiaryId}]/xbrli:entity/xbrli:identifier",
                            Parameters = new ProcessMessageParameters
                            {
                                new ProcessMessageParameter {Name = "RuleIdentifier", Value = "VR.ATO.CHTWTHHLD.000002"},
                                new ProcessMessageParameter { Name = "CHTWTHHLDBEN52", Value = ben.CHTWTHHLDBEN52 }
                            }
                        }));

        }
        #endregion
        #region VR.ATO.CHTWTHHLDBEN.000200
        //IF Beneficiary:period.startDate<> chtwthhld:RP:period.startDate
        //    RETURN VALIDATION MESSAGE
        //ENDIF
        private void VRATOCHTWTHHLDBEN000200(List<ProcessMessageDocument> response)
        {
            if (Parent.CHTWTHHLD55.HasValue)
                response.AddRange(Contexts.Where(ctx => !ctx.StartDate.Value.Equals(Parent.CHTWTHHLD55.Value))
                    .Select(ctx => new ProcessMessageDocument
                    {
                        Code = "CMN.ATO.CHTWTHHLDBEN.000200",
                        Severity = ProcessMessageSeverity.Error,
                        Description = "Beneficiary Reporting period from date does not match reporting party",
                        LongDescription = "All beneficiary and reporting party Reporting period from dates must match",
                        Location = $"/xbrli:xbrl/xbrli:context[{ctx.Id}]",
                        Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CHTWTHHLDBEN.000200" } }
                    }));
        }
        #endregion
        #region VR.ATO.CHTWTHHLDBEN.000201
        //IF Beneficiary:period.endDate<> chtwthhld:RP:period.endDate
        //    RETURN VALIDATION MESSAGE
        //ENDIF
        private void VRATOCHTWTHHLDBEN000201(List<ProcessMessageDocument> response)
        {
            if (Parent.CHTWTHHLD56.HasValue)
                response.AddRange(Contexts.Where(ctx => !ctx.EndDate.Value.Equals(Parent.CHTWTHHLD56.Value))
                    .Select(ctx => new ProcessMessageDocument
                    {
                        Code = "CMN.ATO.CHTWTHHLDBEN.000201",
                        Severity = ProcessMessageSeverity.Error,
                        Description = "Beneficiary Reporting period to date does not match reporting party",
                        LongDescription = "All beneficiary and reporting party Reporting period to dates must match",
                        Location = $"/xbrli:xbrl/xbrli:context[{ctx.Id}]",
                        Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CHTWTHHLDBEN.000201" } }
                    }));
        }
        #endregion
        #region VR.ATO.CHTWTHHLDBEN.000040
        //IF([chtwthhldben52] <> NULL) AND([chtwthhldben52] = ANY OTHER OCCURRENCE OF[chtwthhldben52] IN ANY OTHER SCHEDULE(CHTWTHHLDBEN))
        //  RETURN VALIDATION MESSAGE
        //ENDIF
        //[chtwthhldben52] = CHTWTHHLDBEN:Beneficiary:pyid.02.00:Identifiers.TaxFileNumber.Identifier
        private void VRATOCHTWTHHLDBEN000040(List<ProcessMessageDocument> response)
        {
            response.AddRange(Schedules.Where(ben => !string.IsNullOrWhiteSpace(ben.CHTWTHHLDBEN52))
                .GroupBy(ben => ben.CHTWTHHLDBEN52)
                .Where(g => g.Count() > 1)
                .Select(k => new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CHTWTHHLDBEN.000040",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "Check Beneficiary tax file number",
                    LongDescription = "Beneficiary tax file number must not be reported more than once.",
                    Location = "/xbrli:xbrl/tns:Identifiers.TaxFileNumber.Identifier",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CHTWTHHLDBEN.000040" } }
                }));
        }
        #endregion

        private IEnumerable<CrossFormExtensions.Context> BuildContexts() =>
            Schedules.Where(ben => ben.BeneficiaryOccurrenceIndex > 0).
                Select(ben => new CrossFormExtensions.Context
                {
                    StartDate = ben.BeneficiaryStartDate,
                    EndDate = ben.BeneficiaryEndDate,
                    Index = ben.BeneficiaryOccurrenceIndex,
                    Id = ben.BeneficiaryId
                });
    }
}