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

namespace Ato.CD.Inbound.CTR202602
{
    internal class CrossFormValidatorLS : ICrossFormValidator
    {
        private CTR2026 ParentDocument { get; }
        private LS2017 ChildDocument { get; }
        private List<Context> Contexts { get; }
        public List<ProcessMessageDocument> Response { get; private set; }

        internal CrossFormValidatorLS(CTR2026 report, BusinessDocument childDocument)
        {
            ParentDocument = report;
            ChildDocument = (LS2017)childDocument.ConsumedReport;
            Contexts = ChildDocument.GetContexts();
            Response = new List<ProcessMessageDocument>();
        }

        public List<ProcessMessageDocument> ValidateCrossFormRules()
        {
            //Parent Cross From Validation Rules
            VRATOCTR428102();
            VRATOCTR428190();
            VRATOCTR428191();

            //Child Cross From Validation Rules
            VRATOGEN402009();
            VRATOGEN402010();
            VRATOGEN428045();
            VRATOGEN438000();
            VRATOGEN438001();
            VRATOLS414023();

            return Response;
        }

        #region VR.ATO.CTR.428102

        /*  VR.ATO.CTR.428102
        Companies are required to indicate whether continuity of majority ownership test passes for each year of loss

        Technical Business Rule Format:
        IF ([CTR53] = NULL) AND ([CTR117] > 100000) AND (COUNT(SCHEDULE = "LS") = 1) AND ([LS15] = NULL) AND ([LS16] = NULL) AND ([LS17] = NULL) AND ([LS18] = NULL) AND ([LS19] = NULL) AND ([LS53] = NULL)
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:

        ^CTR53 = CTR:RP:OrganisationDetails.TaxConsolidationStatus.Code
        ^CTR117 = CTR:RP:IncomeTax.Deduction.TaxLossesDeducted.Amount
        ^LS15 = LS:RP.Y0:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
        ^LS16 = LS:RP.Y0-1:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
        ^LS17 = LS:RP.Y0-2:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
        ^LS18 = LS:RP.Y0-3:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
        ^LS19 = LS:RP.Y0-4:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
        ^LS53 = LS:RP.Y0-5P:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
         */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOCTR428102()
        {
            ProcessMessageDocument processMessage;
            bool assertion = string.IsNullOrWhiteSpace(ParentDocument.CTR53) &&
                             ParentDocument.CTR117.GetValueOrDefault() > 100000 &&
                             !ChildDocument.LS15.HasValue && !ChildDocument.LS16.HasValue &&
                             !ChildDocument.LS17.HasValue && !ChildDocument.LS18.HasValue &&
                             !ChildDocument.LS19.HasValue && !ChildDocument.LS53.HasValue;
            if (assertion)
            {
                processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CTR.428102",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Companies are required to indicate whether continuity of majority ownership test passes for each year of loss",
                    LongDescription = @"Companies not part of the consolidated group that have Tax losses deducted of greater than $100.000 (Item 7 Label R) must complete Part B1 on the Losses schedule. Companies are required to indicate whether continuity of majority ownership test passed for each year of loss",
                    Location = "/xbrli:xbrl/tns:IncomeTax.Deduction.TaxLossesDeducted.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CTR.428102" } },
                    DocumentSequence = "parent_doc"
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR53", Value = ParentDocument.CTR53 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR117", Value = CTR2026Validator.GetValueOrEmpty(ParentDocument.CTR117) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS15", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS15) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS16", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS16) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS17", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS17) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS18", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS18) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS19", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS19) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS53", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS53) });
                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.CTR.428102

        #region VR.ATO.CTR.428190

        /*  VR.ATO.CTR.428190
        Total of tax losses C/F to later income year in schedule must equal tax losses C/F to late year in the return
        
        Technical Business Rule Format:
        IF (COUNT(SCHEDULE = "LS") = 1) AND 
        ([CTR175] <> [LS50]) 
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:
        ^CTR175 = CTR:RP:Tax.Losses.CarriedForward.Total.Amount
        ^LS50 = LS:RP.Tax.Losses.CarriedForward.Total.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOCTR428190()
        {
            ProcessMessageDocument processMessage;
            bool assertion = ParentDocument.CTR175.GetValueOrDefault() != ChildDocument.LS50.GetValueOrDefault();

            if (assertion)
            {
                processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CTR.428190",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Total of tax losses C/F to later income year in schedule must equal tax losses C/F to late year in the return",
                    LongDescription = @"Total of the tax losses carried forward to later income years in the losses schedule (Part A Label U) for unconsolidated entities must equal tax losses carried forward to later income years (Item 13 Label U) on the company Income Tax Return form",
                    Location = "/xbrli:xbrl/tns:Tax.Losses.CarriedForward.Total.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CTR.428190" } },
                    DocumentSequence = "parent_doc"
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR175", Value = CTR2026Validator.GetValueOrEmpty(ParentDocument.CTR175) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS50", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS50) });
                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.CTR.428190

        #region VR.ATO.CTR.428191

        /*  VR.ATO.CTR.428191
        Net capital losses carried forward incorrect

        Technical Business Rule Format:
        IF (COUNT(SCHEDULE = "LS") = 1) AND ([CTR176] <> [LS52]) 
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:
        ^CTR176 = CTR:RP:Capital.Losses.CarriedForward.Net.Amount
        ^LS52 = LS:RP:Capital.Losses.CarriedForward.Net.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOCTR428191()
        {
            ProcessMessageDocument processMessage;
            bool assertion = ParentDocument.CTR176.GetValueOrDefault() != ChildDocument.LS52.GetValueOrDefault();

            if (assertion)
            {
                processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CTR.428191",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Net capital losses carried forward incorrect",
                    LongDescription = @"Net capital losses carried forward to later income years - total in Losses schedule for unconsolidated entities is must equal to the Net capital losses carried forward to later income year, Losses information, (Item 13 Label V) on the main income tax return",
                    Location = "/xbrli:xbrl/tns:Capital.Losses.CarriedForward.Net.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CTR.428191" } },
                    DocumentSequence = "parent_doc"
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR176", Value = CTR2026Validator.GetValueOrEmpty(ParentDocument.CTR176) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS52", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS52) });
                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.CTR.428191

        #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
     
        Data Elements:

        ^CTR TFN = CTR:RP:Identifiers.TaxFileNumber.Identifier
        ^LS TFN = LS:RP:Identifiers.TaxFileNumber.Identifier
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN402009()
        {
            ProcessMessageDocument processMessage;
            bool assertion = !ParentDocument.RPIdentifierTFN.Equals(ChildDocument.RPIdentifierTFN);

            if (assertion)
            {
                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" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR TFN", Value = ParentDocument.RPIdentifierTFN });
                processMessage.Parameters.Add(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

        Data Elements:
        
        ^CTR11 = CTR:RP:Identifiers.AustralianBusinessNumber.Identifier
        ^LS3 = LS:RP:Identifiers.AustralianBusinessNumber.Identifier
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN402010()
        {
            ProcessMessageDocument processMessage;
            bool assertion = !string.IsNullOrWhiteSpace(ParentDocument.CTR11) &&
                             !string.IsNullOrWhiteSpace(ChildDocument.LS3) &&
                             !ParentDocument.CTR11.Equals(ChildDocument.LS3);
            if (assertion)
            {
                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" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR11", Value = ParentDocument.CTR11 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS3 ", Value = ChildDocument.LS3 });
                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.GEN.402010

        #region VR.ATO.GEN.428045

        /* VR.ATO.GEN.428045
        Organisation Name in schedule should match Organisation Name in parent return

        Legacy Rule Format:
        IF RP:pyde.xx.xx:OrganisationNameDetails.OrganisationalName.Text 
            IN TUPLE (xbrli\orgname1.xx.xx:OrganisationNameDetails) <> NULL 
            AND RP:pyde.xx.xx:OrganisationNameDetails.OrganisationalName.Text IN TUPLE 
            (xbrli\orgname1.xx.xx:OrganisationNameDetails) <> 
            (PARENT RETURN:RP:pyde.xx.xx:OrganisationNameDetails.OrganisationalName.Text 
            IN TUPLE (xbrli\orgname2.xx.xx:OrganisationNameDetails) 
            WHERE (TUPLE EXPLICIT pyde.xx.xx:OrganisationNameDetails.OrganisationalNameType.Code = "MN") 
            AND  (TUPLE EXPLICIT pyde.xx.xx:OrganisationNameDetails.Currency.Code = "C"))
            RETURN VALIDATION MESSAGE
        ENDIF

         Data Elements:
        
        ^CTR9 = CTR:RP:OrganisationNameDetails.OrganisationalName.Text
        ^LS2 = LS:RP:OrganisationNameDetails.OrganisationalName.Text
        ^CTR228 = CTR:RP:OrganisationNameDetails.OrganisationalNameType.Code
        ^CTR285 = CTR:RP:OrganisationNameDetails.Currency.Code
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN428045()
        {
            ProcessMessageDocument processMessage;
            bool assertion = !string.IsNullOrWhiteSpace(ParentDocument.CTR9) &&
                             !string.IsNullOrWhiteSpace(ChildDocument.LS2) &&
                             !ParentDocument.CTR9.ToUpper().Equals(ChildDocument.LS2.ToUpper()) &&
                             ParentDocument.CTR228.Equals("MN") && ParentDocument.CTR285.Equals("C");
            if (assertion)
            {
                processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.428045",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Organisation Name in schedule should match Organisation Name in parent return",
                    Location = "/xbrli:xbrl/tns:OrganisationNameDetails/tns:OrganisationNameDetails.OrganisationalName.Text",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.428045" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR9", Value = ParentDocument.CTR9 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS2 ", Value = ChildDocument.LS2 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR228", Value = ParentDocument.CTR228 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR285", Value = ParentDocument.CTR285 });
                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.GEN.428045

        #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

        Data Elements:

        ^CTR Start Date = CTR Start Date
        ^LS Start Date = LS Start Date
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN438000()
        {
            Response.AddRange(from context in Contexts
                              where context.StartDate.GetValueOrDefault() != ParentDocument.RPStartDate.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 = "CTR Start Date", Value = CTR2026Validator.GetValueOrEmptyDate(ParentDocument.RPStartDate) },
                                      new ProcessMessageParameter { Name = "LS Start Date", Value = CTR2026Validator.GetValueOrEmptyDate(context.StartDate) }
                                  }
                              });
        }

        #endregion // VR.ATO.GEN.438000

        #region VR.ATO.GEN.438001

        /*  VR.ATO.GEN.438001
        Period end date within context on schedule doesn't match 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

        Data Elements:

        ^CTR End Date = CTR End Date
        ^LS End Date = LS End Date
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN438001()
        {
            Response.AddRange(from context in Contexts
                              where context.EndDate.GetValueOrDefault() != ParentDocument.RPEndDate.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 = "CTR End Date", Value = CTR2026Validator.GetValueOrEmptyDate(ParentDocument.RPEndDate) },
                                      new ProcessMessageParameter { Name = "LS End Date", Value = CTR2026Validator.GetValueOrEmptyDate(context.EndDate) }
                                  }
                              });
        }

        #endregion // VR.ATO.GEN.438001

        #region VR.ATO.LS.414023

        /*  VR.ATO.LS.414023
        A company is required to indicate whether a changeover time occurred by selecting either "yes" or "no".

        Legacy Rule Format:
        IF (PARENT RETURN = "CTR") AND [LS25] = NULL
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:
            
        ^LS25 = tns:Tax.Losses.ChangeOfOwnershipOrControlAfterReferenceTime.Indicator
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOLS414023()
        {
            bool assertion = !ChildDocument.LS25.HasValue;

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.LS.414023",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Answer to changeover time question is required",
                    Location = "/xbrli:xbrl/tns:Tax.Losses.ChangeOfOwnershipOrControlAfterReferenceTime.Indicator",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.LS.414023" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "LS25", Value = CTR2026Validator.GetValueOrEmpty(ChildDocument.LS25) });
                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.LS.414023
    }
}