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

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

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

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

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

            return Response;
        }

        #region VR.ATO.CTR.428187

        /*  VR.ATO.CTR.428187
        Total net capital losses C/F must equal Label V Net Capital Losses C/F in the Company Income Tax Form

        Legacy Rule Format:
        IF  (COUNT(SCHEDULE = "CGLS") = 1) AND ([CGLS34] > 0) AND ([CTR176] <> [CGLS34])
            RETURN VALIDATION MESSAGE
        ENDIF

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

            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.CTR.428187",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Total net capital losses C/F must equal Label V Net Capital Losses C/F in the Company Income Tax Form",
                    LongDescription = @"The total amount of Net capital losses carried forward to later income year on the Losses schedule for a consolidated group (Part A 10 Label V) must equal the amount of Net capital losses carried forward to later income year (Item 13 Label V) on the Company tax return",
                    Location = "/xbrli:xbrl/tns:Capital.Losses.CarriedForward.Net.Amount",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.CTR.428187" } },
                    DocumentSequence = "parent_doc"
                };

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

        #endregion // VR.ATO.CTR.428187

        #region VR.ATO.CGLS.404006

        /*  VR.ATO.CGLS.404006
        The total amount of tax losses deducted on the CGLS for a consolidated group must equal the amount of tax losses deducted on the CTR.

        Legacy Rule Format:
        IF [CGLS107] > 0 AND [CGLS107] <>[CTR117]
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:

        ^CGLS107 = CGLS:RP:Tax.Losses.Deducted.Amount
        ^CTR117 = CTR:RP:IncomeTax.Deduction.TaxLossesDeducted.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOCGLS404006()
        {
            ProcessMessageDocument processMessage;
            bool assertion = ChildDocument.CGLS107.GetValueOrDefault() > 0 && ChildDocument.CGLS107.GetValueOrDefault() != ParentDocument.CTR117.GetValueOrDefault();

            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.CGLS.404212",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Total tax losses deducted must equal tax losses deducted on the Company Return",
                    LongDescription = @"(Tax losses deducted - Total) must equal (Tax losses deducted) on the Company Return",
                    Location = "/xbrli:xbrl/tns:Tax.Losses.Deducted.Amount[@contextRef='" + ChildDocument.RPTOTId + "']",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.CGLS.404006" } },
                };

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

        #endregion // VR.ATO.CGLS.404006

        #region VR.ATO.CGLS.404011

        /*  VR.ATO.CGLS.404011
        The total amount of tax losses carried forward to later income years on the CGLS for a consolidated group must equal the amount of tax losses carried forward to later income years on the CTR.

        Legacy Rule Format:
        IF [CGLS19] > 0 AND [CGLS19] <> [CTR175]
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:
      
        ^CGLS19 = CGLS:RP:Tax.Losses.CarriedForward.Total.Amount
        ^CTR175 = CTR:RP:Tax.Losses.CarriedForward.Total.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOCGLS404011()
        {
            ProcessMessageDocument processMessage;
            bool assertion = ChildDocument.CGLS19.GetValueOrDefault() > 0 && ChildDocument.CGLS19.GetValueOrDefault() != ParentDocument.CTR175.GetValueOrDefault();
          
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.CGLS.404011",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Tax losses carried forward must equal corresponding field on the Company Return",
                    LongDescription = @"(Tax losses carried forward to later income years - Total) must equal (Tax losses carried forward to later income years) on the Company Return",
                    Location = "/xbrli:xbrl/tns:Tax.Losses.CarriedForward.Total.Amount[@contextRef='" + ChildDocument.RPTOTId + "']",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.CGLS.404011" } },
                };

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

        #endregion // VR.ATO.CGLS.404011

        #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:entity.identifier.TFN
        ^CGLS TFN  = CGLS:RP:entity.identifier.TFN
        */
        [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 = "CGLS 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
        ^CGLS3 = CGLS:RP:Identifiers.AustralianBusinessNumber.Identifier
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN402010()
        {
            ProcessMessageDocument processMessage;
            bool assertion = !string.IsNullOrWhiteSpace(ParentDocument.CTR11) &&
                             !string.IsNullOrWhiteSpace(ChildDocument.CGLS3) &&
                             !ParentDocument.CTR11.Equals(ChildDocument.CGLS3);
            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 = "CGLS3", Value = ChildDocument.CGLS3 });
                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\organisationname1.xx.xx:OrganisationNameDetails) <> NULL
        AND RP:pyde.xx.xx:OrganisationNameDetails.OrganisationalName.Text IN TUPLE (xbrli\organisationname1.xx.xx:OrganisationNameDetails) <> 
        (PARENT RETURN:RP:pyde.xx.xx:OrganisationNameDetails.OrganisationalName.Text IN TUPLE (xbrli\organisationname2.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
        ^CGLS2 = CGLS:RP:OrganisationNameDetails.OrganisationalName.Text
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOGEN428045()
        {
            ProcessMessageDocument processMessage;
            bool assertion = !string.IsNullOrWhiteSpace(ParentDocument.CTR9) &&
                             !string.IsNullOrWhiteSpace(ChildDocument.CGLS2) &&
                             !ParentDocument.CTR9.ToUpper().Equals(ChildDocument.CGLS2.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 = "CGLS2", Value = ChildDocument.CGLS2 });
                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
        ^CGLS Start Date = CGLS 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 = "CGLS 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 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

        Data Elements:
        
        ^CTR End Date = CTR End Date
        ^CGLS End Date = CGLS 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 = "CGLS End Date", Value = CTR2026Validator.GetValueOrEmptyDate(context.EndDate) }
                                  }
                              });
        }

        #endregion // VR.ATO.GEN.438001

        private List<Context> GetContexts()
        {
            var contexts = new List<Context>();

            contexts.AddContext(ChildDocument.RPStartDate, ChildDocument.RPEndDate, ChildDocument.RPOccurrenceIndex).
                         AddContext(ChildDocument.RPCOTPStartDate, ChildDocument.RPCOTPEndDate, ChildDocument.RPCOTPOccurrenceIndex).
                         AddContext(ChildDocument.RPCOTFStartDate, ChildDocument.RPCOTFEndDate, ChildDocument.RPCOTFOccurrenceIndex).
                         AddContext(ChildDocument.RPCOTTStartDate, ChildDocument.RPCOTTEndDate, ChildDocument.RPCOTTOccurrenceIndex).
                         AddContext(ChildDocument.RPGRPStartDate, ChildDocument.RPGRPEndDate, ChildDocument.RPGRPOccurrenceIndex).
                         AddContext(ChildDocument.RPTRFDStartDate, ChildDocument.RPTRFDEndDate, ChildDocument.RPTRFDOccurrenceIndex).
                         AddContext(ChildDocument.RPTOTStartDate, ChildDocument.RPTOTEndDate, ChildDocument.RPTOTOccurrenceIndex).
                         AddContext(ChildDocument.RPY0StartDate, ChildDocument.RPY0EndDate, ChildDocument.RPY0OccurrenceIndex).
                         AddContext(ChildDocument.RPY0Minus1StartDate, ChildDocument.RPY0Minus1EndDate, ChildDocument.RPY0Minus1OccurrenceIndex).
                         AddContext(ChildDocument.RPY0Minus2StartDate, ChildDocument.RPY0Minus2EndDate, ChildDocument.RPY0Minus2OccurrenceIndex).
                         AddContext(ChildDocument.RPY0Minus3StartDate, ChildDocument.RPY0Minus3EndDate, ChildDocument.RPY0Minus3OccurrenceIndex).
                         AddContext(ChildDocument.RPY0Minus4PStartDate, ChildDocument.RPY0Minus4PEndDate, ChildDocument.RPY0Minus4POccurrenceIndex);

            if (ChildDocument.TRFRContextCollection != null)
            {
                foreach (var ChildRPTRFR in ChildDocument.TRFRContextCollection)
                {
                    contexts.AddContext(ChildRPTRFR.StartDate, ChildRPTRFR.EndDate, ChildRPTRFR.OccurrenceIndex);
                }
            }

            if (ChildDocument.JEContextCollection != null)
            {
                foreach (var JEContext in ChildDocument.JEContextCollection)
                {
                    contexts.AddContext(JEContext.StartDate, JEContext.EndDate, JEContext.OccurrenceIndex);
                }
            }

            return contexts;
        }
    }
}