using Ato.CD.Inbound.Shared;
using Ato.CD.Inbound.Shared201702;
using Ato.EN.IntegrationServices.CodeGenerationLS;
using Ato.EN.IntegrationServices.CodeGenerationTRT;
using DataContracts;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;

namespace Ato.CD.Inbound.TRT202502
{
    public class CrossFormValidatorLS : ICrossFormValidator
    {
        private LS2017 childDocument { get; set; }

        private List<Context> contexts { get; set; }

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

        private TRT2025 parentDocument { get; set; }

        public CrossFormValidatorLS(TRT2025 parent, object child)
        {
            childDocument = (LS2017)child;
            parentDocument = parent;
            contexts = childDocument.GetContexts();
            response = new List<ProcessMessageDocument>();
        }

        public List<ProcessMessageDocument> ValidateCrossFormRules()
        {
            //Parent form cross form rules
            VRATOTRT432208();
            VRATOTRT432212();
            VRATOTRT432215();

            //Child form cross form rules
            VRATOLS414022();
            VRATOGEN402009();
            VRATOGEN402010();
            VRATOGEN438000();
            VRATOGEN438001();
            return response;
        }

        #region Validation Rules

        #region VR.ATO.TRT.432208

        /*  VR.ATO.TRT.432208
        Public unit trust (listed other than cash management unit trust) that have Tax losses deducted of greater than $100,000 must complete Part B1 of the Losses schedule for unconsolidated entities. Trusts are required to indicate whether continuity of majority ownership test passed for each year of loss.

        Legacy Rule Format:
        ^TRT32 = '179' AND ^TRT144 > 100000 AND CountDocument('LS') = 1 AND ^LS15 = NULL AND ^LS16 = NULL AND ^LS17 = NULL AND ^LS18 = NULL AND ^LS19 = NULL AND ^LS53 = NULL

        Technical Business Rule Format:
        ^TRT32 = '179' AND ^TRT144 > 100000 AND CountDocument('LS') = 1 AND ^LS15 = NULL AND ^LS16 = NULL AND ^LS17 = NULL AND ^LS18 = NULL AND ^LS19 = NULL AND ^LS53 = NULL

        Data Elements:
    
        ^TRT144 = TRT:RP:BusinessDetails:Income:TaxLossesDeducted:IncomeTax.Deduction.TaxLossesDeducted.Amount

        ^TRT32 = TRT:RP:TypeOfTrust:OrganisationDetails.OrganisationType.Code
    
        ^LS15 = LS:RP:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
    
        ^LS16 = LS:RP:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
    
        ^LS17 = LS:RP:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
    
        ^LS18 = LS:RP:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
    
        ^LS19 = LS:RP:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
    
        ^LS53 = LS:RP:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
        
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOTRT432208()
        {
            bool assertion = parentDocument.TRT32 == @"179" && parentDocument.TRT144.GetValueOrDefault() > 100000 && childDocument.LS15 == null && childDocument.LS16 == null && childDocument.LS17 == null && childDocument.LS18 == null && childDocument.LS19 == null && childDocument.LS53 == null;

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.TRT.432208",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Widely held trusts must indicate whether continuity of majority ownership test passed for each year of loss",
                    LongDescription = @"Public unit trust (listed other than cash management unit trust) that have Tax losses deducted of greater than $100,000 must complete Part B1 of the Losses schedule for unconsolidated entities",
                    Location = "/tns:TRT/tns:RP/tns:BusinessDetails/tns:Income/tns:TaxLossesDeductedTaxDeductionA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.TRT.432208" },
                        new ProcessMessageParameter() { Name = "TRT144", Value = parentDocument.TRT144.GetValueOrDefault().ToString() },
                        new ProcessMessageParameter() { Name = "TRT32", Value = "179" },
                        new ProcessMessageParameter() { Name = "LS15", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS15) },
                        new ProcessMessageParameter() { Name = "LS16", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS16) },
                        new ProcessMessageParameter() { Name = "LS17", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS17) },
                        new ProcessMessageParameter() { Name = "LS18", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS18) },
                        new ProcessMessageParameter() { Name = "LS19", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS19) },
                        new ProcessMessageParameter() { Name = "LS53", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS53) }
                    },
                    DocumentSequence = "parent_doc"
                });
            }
        }
        #endregion // VR.ATO.TRT.432208

        #region VR.ATO.TRT.432212

        /*  VR.ATO.TRT.432212
        Total of the tax losses carried forward to later income years in the losses schedule for unconsolidated entities must equal tax losses carried forward to later income years on the main income tax return.

        Legacy Rule Format:
        CountDocument('LS') = 1 AND ^LS50 <> ^TRT145

        Technical Business Rule Format:
        CountDocument('LS') = 1 AND ^LS50 <> ^TRT145

        Data Elements:
    
        ^TRT145 = TRT:RP:BusinessDetails:Income:Tax.Losses.CarriedForward.LaterIncomeYearsTotal.Amount
    
        ^LS50 = LS:RP:Tax.Losses.CarriedForward.Total.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOTRT432212()
        {
            bool assertion = childDocument.LS50.GetValueOrDefault() != parentDocument.TRT145.GetValueOrDefault();

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.434086",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Tax losses carried forward to later income years in schedule must equal amount in main form",
                    LongDescription = @"The total of the 'Tax losses carried forward to later income years'  for unconsolidated entities in the Losses schedule must equal 'Tax losses carried forward to later income years' on the main form",
                    Location = "/tns:TRT/tns:RP/tns:BusinessDetails/tns:Income/tns:TaxLossesCarriedForwardLaterIncomeYearsTotalA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.TRT.432212" },
                        new ProcessMessageParameter() { Name = "TRT145", Value = parentDocument.TRT145.GetValueOrDefault().ToString() },
                        new ProcessMessageParameter() { Name = "LS50", Value = childDocument.LS50.GetValueOrDefault().ToString() }
                    },
                    DocumentSequence = "parent_doc"
                });
            }
        }
        #endregion // VR.ATO.TRT.432212

        #region VR.ATO.TRT.432215

        /*  VR.ATO.TRT.432215
        Net capital losses carried forward to later income years - Total in the Losses schedule for unconsolidated entities is equal to the Net capital losses carried forward to later income years on the main income tax return.

        Legacy Rule Format:
        CountDocument('LS') = 1 AND ^LS52 <> ^TRT475

        Technical Business Rule Format:
        CountDocument('LS') = 1 AND ^LS52 <> ^TRT475

        Data Elements:
    
        ^TRT475 = TRT:RP:BusinessDetails:Income:Capital.Losses.CarriedForward.Net.Amount
    
        ^LS52 = LS:RP:Capital.Losses.CarriedForward.Net.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOTRT432215()
        {
            bool assertion = childDocument.LS52.GetValueOrDefault() != parentDocument.TRT475.GetValueOrDefault();

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.434087",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Net capital losses carried forward to later income years must equal amount in Losses schedule",
                    LongDescription = @"The total of the 'Net capital losses carried forward to later income years'  for unconsolidated entities in the Losses schedule must equal 'Net capital losses carried forward to later income years' on the main form",
                    Location = "/tns:TRT/tns:RP/tns:BusinessDetails/tns:Income/tns:CapitalLossesCarriedForwardNetA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.TRT.432215" },
                        new ProcessMessageParameter() { Name = "TRT475", Value = parentDocument.TRT475.GetValueOrDefault().ToString() },
                        new ProcessMessageParameter() { Name = "LS52", Value = childDocument.LS52.GetValueOrDefault().ToString() }
                    },
                    DocumentSequence = "parent_doc"
                });
            }
        }
        #endregion // VR.ATO.TRT.432215

        #region VR.ATO.LS.414022

        /*  VR.ATO.LS.414022
        Questions relating to unrealised losses are to be completed by companies only. Funds and trusts are not required to complete.
        
        Legacy Rule Format:
        IF (PARENT RETURN<>"CTR") AND ([LS25] <> NULL OR [LS26] <> NULL OR [LS27] <> NULL OR [LS28] <> NULL)
            RETURN VALIDATION MESSAGE
        ENDIF

        Technical Business Rule Format:
        IF (PARENT RETURN<>"CTR") AND ([LS25] <> NULL OR [LS26] <> NULL OR [LS27] <> NULL OR [LS28] <> NULL)
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:

        ^LS25 = LS:RP:Tax.Losses.ChangeOfOwnershipOrControlAfterReferenceTime.Indicator

        ^LS26 = LS:RP:Tax.Losses.MaximumNetAssetValueTestPassedAtChangeoverTime.Indicator

        ^LS27 = LS:RP:Tax.Losses.UnrealisedNetLossAtChangeoverTime.Indicator

        ^LS28 = LS:RP:Tax.Losses.UnrealisedNetLossAtChangeoverTime.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOLS414022()
        {
            bool assertion = childDocument.LS25.HasValue || childDocument.LS26.HasValue || childDocument.LS27.HasValue || childDocument.LS28.HasValue;

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.LS.414022",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Unrealised losses are not required",
                    Location = "/xbrli:xbrl/tns:Tax.Losses.ChangeOfOwnershipOrControlAfterReferenceTime.Indicator",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.LS.414022" },
                        new ProcessMessageParameter { Name = "LS25", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS25) },
                        new ProcessMessageParameter { Name = "LS26", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS26) },
                        new ProcessMessageParameter { Name = "LS27", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS27) },
                        new ProcessMessageParameter { Name = "LS28", Value = TRT2025Validator.GetValueOrEmpty(childDocument.LS28) }
                    }
                };

                response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.LS.414022

        #region VR.ATO.GEN.402009

        /*  VR.ATO.GEN.402009
        Your supplied TFN does not match the TFN supplied on the form it was submitted with

        Legacy Rule Format:
        IF (RP:entity.identifier.TFN <> PARENT RETURN:RP:entity.identifier.TFN)
            RETURN VALIDATION MESSAGE
        ENDIF

        Technical Business Rule Format:
        IF (RP:entity.identifier.TFN <> PARENT RETURN:RP:entity.identifier.TFN)
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:

        ^TRT5 = TRT:RP:Identifiers.TaxFileNumber.Identifier
            
        ^LS TFN = LS:RP:Identifiers.TaxFileNumber.Identifier
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN402009()
        {
            bool assertion = !parentDocument.TRT5.Equals(childDocument.RPIdentifierTFN);

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.402009",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Your supplied TFN does not match the TFN supplied on the form it was submitted with",
                    LongDescription = @"Your supplied TFN does not match the TFN supplied on the parent form it was submitted with",
                    Location = "/xbrli:xbrl/xbrli:context/xbrli:entity/xbrli:identifier",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.402009" },
                        new ProcessMessageParameter { Name = "TRT5", Value = parentDocument.TRT5 },
                        new ProcessMessageParameter { Name= "LS TFN", Value= childDocument.RPIdentifierTFN }
                    }
                };


                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.GEN.402009

        #region VR.ATO.GEN.402010

        /*  VR.ATO.GEN.402010
        Your supplied ABN does not match the ABN supplied on the form it was submitted with

        Legacy Rule Format:
        IF (RP:pyid.xx.xx:Identifiers.AustralianBusinessNumber.Identifier <> NULLORBLANK) AND (PARENT RETURN:RP:pyid.xx.xx:Identifiers.AustralianBusinessNumber.Identifier <> NULLORBLANK) AND (RP:pyid.xx.xx:Identifiers.AustralianBusinessNumber.Identifier <> PARENT RETURN:RP:pyid.xx.xx:Identifiers.AustralianBusinessNumber.Identifier)
            RETURN VALIDATION MESSAGE
        ENDIF

        Technical Business Rule Format:
        IF (RP:pyid.xx.xx:Identifiers.AustralianBusinessNumber.Identifier <> NULLORBLANK) AND (PARENT RETURN:RP:pyid.xx.xx:Identifiers.AustralianBusinessNumber.Identifier <> NULLORBLANK) AND (RP:pyid.xx.xx:Identifiers.AustralianBusinessNumber.Identifier <> PARENT RETURN:RP:pyid.xx.xx:Identifiers.AustralianBusinessNumber.Identifier)
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:
        
        ^TRT7 = TRT:RP:Identifiers.AustralianBusinessNumber.Identifier
        
        ^LS3 = LS:RP:Identifiers.AustralianBusinessNumber.Identifier
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN402010()
        {
            bool assertion = !string.IsNullOrWhiteSpace(parentDocument.TRT7) &&
                             !string.IsNullOrWhiteSpace(childDocument.LS3) &&
                             !parentDocument.TRT7.Equals(childDocument.LS3);
            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.402010",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Your supplied ABN does not match the ABN supplied on the form it was submitted with",
                    LongDescription = @"Your supplied ABN does not match the ABN supplied on the parent form it was submitted with",
                    Location = "/xbrli:xbrl/tns:Identifiers.AustralianBusinessNumber.Identifier",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.402010" },
                        new ProcessMessageParameter { Name = "TRT7", Value = parentDocument.TRT7 },
                        new ProcessMessageParameter { Name = "LS3", Value = childDocument.LS3 }
                    }
                };

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.GEN.402010

        #region VR.ATO.GEN.438000

        /*  VR.ATO.GEN.438000
        Period start date within context on the schedule does not match period start date within PARENT RETURN:reporting party context

        Legacy Rule Format:
        IF (period.startDate WHERE CONTEXT(ALL)) <> PARENT RETURN:RP:period.startDate
            RETURN VALIDATION MESSAGE
        ENDIF

        Technical Business Rule Format:
        IF (period.startDate WHERE CONTEXT(ALL)) <> PARENT RETURN:RP:period.startDate
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:
        
        ^TRT573 = TRT:RP:Period.Start.Date

        ^ContextStartDate = context.StartDate
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN438000()
        {
            response.AddRange(from context in contexts
                              where context.StartDate.GetValueOrDefault() != parentDocument.TRT573.GetValueOrDefault()
                              select new ProcessMessageDocument
                              {
                                  Code = "CMN.ATO.GEN.438000",
                                  Severity = ProcessMessageSeverity.Error,
                                  Description = @"The context period start date is incorrect.",
                                  LongDescription = @"Period start date within context on the schedule must match period start date within the parent return reporting party context",
                                  Location = $"/xbrli:xbrl/xbrli:context[{context.Index}]/xbrli:period/xbrli:startDate",
                                  Parameters = new ProcessMessageParameters
                                  {
                                      new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438000" },
                                      new ProcessMessageParameter { Name = "TRT573", Value = TRT2025Validator.GetValueOrEmptyDate(parentDocument.TRT573) },
                                      new ProcessMessageParameter { Name = "ContextStartDate", Value = TRT2025Validator.GetValueOrEmptyDate(context.StartDate) }
                                  }
                              });
        }
        #endregion // VR.ATO.GEN.438000

        #region VR.ATO.GEN.438001

        /*  VR.ATO.GEN.438001
        Period end date within context on the schedule does not match period end date within PARENT RETURN:reporting party context

        Legacy Rule Format:
        IF (period.endDate WHERE CONTEXT(ALL)) <> PARENT RETURN:RP:period.endDate
            RETURN VALIDATION MESSAGE
        ENDIF

        Technical Business Rule Format:
        IF (period.endDate WHERE CONTEXT(ALL)) <> PARENT RETURN:RP:period.endDate
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:
            
        ^TRT574 = TRT:RP:Period.End.Date
            
        ^ContextEndDate = context.EndDate
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN438001()
        {
            response.AddRange(from context in contexts
                              where context.EndDate.GetValueOrDefault() != parentDocument.TRT574.GetValueOrDefault()
                              select new ProcessMessageDocument
                              {
                                  Code = "CMN.ATO.GEN.438001",
                                  Severity = ProcessMessageSeverity.Error,
                                  Description = @"The context period end date is incorrect.",
                                  LongDescription = @"Period end date within context on the schedule must match period end date within the parent return reporting party context",
                                  Location = $"/xbrli:xbrl/xbrli:context[{context.Index}]/xbrli:period/xbrli:endDate",
                                  Parameters = new ProcessMessageParameters
                                  {
                                      new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438001" },
                                      new ProcessMessageParameter { Name = "TRT574", Value = TRT2025Validator.GetValueOrEmptyDate(parentDocument.TRT574) },
                                      new ProcessMessageParameter { Name = "ContextEndDate", Value = TRT2025Validator.GetValueOrEmptyDate(context.EndDate) }
                                  }
                              });
        }
        #endregion // VR.ATO.GEN.438001

        #endregion Validation Rules
    }
}