using Ato.CD.Inbound.Shared;
using Ato.EN.IntegrationServices.CodeGenerationPSS;
using Ato.EN.IntegrationServices.CodeGenerationPTR;
using DataContracts;
using System.Collections.Generic;
using System.Linq;
using VaTS;
using static Ato.CD.Inbound.Shared.ValidatorHelpers;

namespace Ato.CD.Inbound.PTR202602
{
    public class CrossFormValidatorPSS : ICrossFormValidator
    {
        private PTR2025 ParentDocument { get; }

        private PSS2018 ChildDocument { get; }

        public List<ProcessMessageDocument> Response { get; private set; }

        public CrossFormValidatorPSS(PTR2025 report, BusinessDocument childDocument)
        {
            ParentDocument = report;
            ChildDocument = (PSS2018)childDocument.ConsumedReport;
            Response = new List<ProcessMessageDocument>();
        }

        public List<ProcessMessageDocument> ValidateCrossFormRules()
        {
            VRATOPSS000035();
            VRATOPSS000036();

            VRATOPTR430020();
            VRATOPTR430025();

            return Response;
        }

        #region VR.ATO.PTR.430020
        /*
            VR.ATO.PTR.430020

            Gross payment where ABN not quoted must equal sum of payments on schedule

            Technical Business Rule Format:
            CountDocument('PSS') > 0 AND (^PTR35 + ^PTR36) <> Sum(^PSS19)

            Data Elements:

            ^PTR35 = PTR:RP:Income:BusinessIncomeAndExpenses:IncomePrimaryProduction:RemunerationABNNotQuotedPaymentGrossA

            ^PTR36 = PTR:RP:Income:BusinessIncomeAndExpenses:IncomeNonPrimaryProduction:RemunerationABNNotQuotedPaymentGrossA
                         
            ^PSS19 = PSS:RP.Payer.{PSSeqNum}:tns:Remuneration.ABNNotQuotedPaymentGross.Amount
        */

        public void VRATOPTR430020()
        {
            bool assertion = (ParentDocument.PTR35.GetValueOrDefault() + ParentDocument.PTR36.GetValueOrDefault()) 
                != (ChildDocument.RPPayerPSSeqNumContextCollection == null ? 0 :ChildDocument.RPPayerPSSeqNumContextCollection.Where(payer => payer.PSS19.HasValue).Sum(payer => payer.PSS19));

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.430020",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Gross payment where ABN not quoted must equal sum of payments on schedule",
                    LongDescription = @"The sum of gross payment with indicator 'N' in the Payment Summary schedule must equal the sum of Primary production and Non-primary production Gross payments where ABN not quoted on main return form",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:BusinessIncomeAndExpenses/tns:IncomePrimaryProduction/tns:RemunerationABNNotQuotedPaymentGrossA",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430020" },
                        new ProcessMessageParameter { Name = "PTR35", Value = ParentDocument.PTR35.HasValue ? ParentDocument.PTR35.GetValueOrDefault().ToString() : "null"},
                        new ProcessMessageParameter { Name = "PTR36", Value = ParentDocument.PTR36.HasValue ? ParentDocument.PTR36.GetValueOrDefault().ToString() : "null" },
                        new ProcessMessageParameter { Name = "SUM(PSS19)", Value =  ChildDocument.RPPayerPSSeqNumContextCollection == null ? "null" : ChildDocument.RPPayerPSSeqNumContextCollection.Where(payer => payer.PSS19.HasValue).Sum(payer => payer.PSS19).GetValueOrDefault().ToString()},
                    },
                    DocumentSequence = "parent_doc"
                });
            }
        }

        #endregion VR.ATO.PTR.430020

        #region VR.ATO.PTR.430025
        /*
            VR.ATO.PTR.430025

            Gross payment - Foreign Resident Withholding (excluding capital gains) is incorrect

            Technical Business Rule Format:
            CountDocument('PSS') > 0 AND ^PTR38 <> Sum(^PSS18)

            Data Elements:

            ^PTR38 = PTR:RP:Income:BusinessIncomeAndExpenses:IncomeNonPrimaryProduction:RemunerationPaymentToForeignResidentGrossA
                         
            ^PSS18 = PSS18
        */

        public void VRATOPTR430025()
        {
            bool assertion = ParentDocument.PTR38.GetValueOrDefault() != (ChildDocument.RPPayerPSSeqNumContextCollection == null ? 0 : 
                ChildDocument.RPPayerPSSeqNumContextCollection.Where(payer => payer.PSS18.HasValue).Sum(payer => payer.PSS18));

            if (assertion)
            {
                Response.Add( new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.PTR.430025",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Gross payment - Foreign Resident Withholding (excluding capital gains) is incorrect",
                    LongDescription = @"The sum of gross payments with indicator 'F' in the Payment Summary schedule must be equal to the sum of total gross payment subject to foreign resident withholding (excluding capital gains) primary production and total gross payment subject to foreign resident withholding (excluding capital gains) non-primary production on the main return form",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:BusinessIncomeAndExpenses/tns:IncomeNonPrimaryProduction/tns:RemunerationPaymentToForeignResidentGrossA",
                    Parameters = new ProcessMessageParameters {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430025" },
                        new ProcessMessageParameter { Name = "PTR38", Value = ParentDocument.PTR38.HasValue ? ParentDocument.PTR38.GetValueOrDefault().ToString() : "null" },
                        new ProcessMessageParameter { Name = "Sum(PSS18)", Value = ChildDocument.RPPayerPSSeqNumContextCollection == null ? "null" : ChildDocument.RPPayerPSSeqNumContextCollection.Where(payer => payer.PSS18.HasValue).Sum(payer => payer.PSS18).GetValueOrDefault().ToString()},
                    },
                    DocumentSequence = "parent_doc"
                });
            }
        }

        #endregion VR.ATO.PTR.430025

        #region VR.ATO.PSS.000036
        /*  VR.ATO.PSS.000036
            WHERE IN CONTEXT (RP.Payer.{PSSeqNum)
            IF (RP.Payer.{PSSeqNum}.entity.identifier.TFN <> PARENT RETURN:RP.entity.identifier.TFN)
               RETURN VALIDATION MESSAGE
            ENDIF
       */
        public void VRATOPSS000036()
        {
            if (ChildDocument.RPPayerPSSeqNumContextCollection != null)
                Response.AddRange(ChildDocument.RPPayerPSSeqNumContextCollection
                    .Where(p => p.IdentifierTFN != ParentDocument.PTR5)
                    .Select((p, i) => new { RPPayer = p, Idx = i }).Select(p => new ProcessMessageDocument
                    {
                        Code = "CMN.ATO.PSS.000036",
                        Severity = ProcessMessageSeverity.Error,
                        Description = "Your supplied TFN does not match the TFN supplied on the form it was submitted with",
                        Location = p.Idx == 0 ? "xbrli:xbrl/xbrli:context/xbrli:entity/xbrli:identifier" : $"xbrli:xbrl/xbrli:context[{p.Idx + 1}]/xbrli:entity/xbrli:identifier",
                        Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PSS.000036" } }
                    }));
        }
        #endregion

        #region VR.ATO.PSS.000035
        /*  VR.ATO.PSS.000035
            IF PARENT RETURN <> “IITR”
               AND ([PSS20] <> NULLORBLANK OR [PSS21] <> NULLORBLANK OR [PSS31] <> NULLORBLANK OR [PSS24] <> NULLORBLANK OR [PSS25] <> NULLORBLANK OR [PSS32] <> NULLORBLANK)
                 RETURN VALIDATION MESSAGE
              ENDIF

              [PSS20] = PSS:RP.Payer.{PSSeqNum}:tns:Remuneration.VoluntaryAgreementGross.Amount
              [PSS21] = PSS:RP.Payer.{PSSeqNum}:tns:Remuneration.LabourHireArrangementPaymentGross.Amount
              [PSS24] = PSS:RP.Payer.{PSSeqNum}:tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessVoluntaryAgreement.Amount
              [PSS25] = PSS:RP.Payer.{PSSeqNum}:tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessLabourHireOrOtherPayments.Amount
              [PSS31] = PSS:RP.Payer.{PSSeqNum}:tns:Remuneration.PersonalServicesIncome.AttributedGross.Amount
              [PSS32] = PSS:RP.Payer.{PSSeqNum}:tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldPersonalServicesIncome.Amount   
       */
        public void VRATOPSS000035()
        {
            if (ChildDocument.RPPayerPSSeqNumContextCollection != null)
                Response.AddRange(ChildDocument.RPPayerPSSeqNumContextCollection
                    .Where(p => p.PSS20.HasValue || p.PSS21.HasValue || p.PSS24.HasValue || p.PSS25.HasValue ||
                                p.PSS31.HasValue || p.PSS32.HasValue).Select(p =>
                        new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.PSS.000035",
                            Severity = ProcessMessageSeverity.Error,
                            Description = "Payment Type not applicable to Non-individual income tax return",
                            Location = $"/xbrli:xbrl/tns:Remuneration.PaymentToForeignResidentGross.Amount[contextRef=\"{p.Id}\"]",
                            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PSS.000035" } }
                        }
                    ));
        }
        #endregion

    }
}