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

namespace Ato.CD.Inbound.CTR202502
{
    internal class CrossFormValidatorCGLS : ICrossFormValidator
    {
        private CTR2025 ParentDocument { get; }

        private CGLS2017 ChildDocument { get; }

        private List<Context> Contexts { get; }

        internal CrossFormValidatorCGLS(CTR2025 report, BusinessDocument childDocument)
        {
            ParentDocument = report;
            ChildDocument = (CGLS2017)childDocument.ConsumedReport;
            Contexts = GetContexts();
        }

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

            VRATOCTR428187(response);
            VRATOGEN438000(response);
            VRATOGEN438001(response);
            VRATOGEN402010(response);
            VRATOGEN402009(response);
            VRATOGEN428045(response);
            VRATOCGLS404006(response);
            VRATOCGLS404011(response);

            return response;
        }

        //CTR-CGLS

        #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
                    
                    [CGLS34] = CGLS:RP.TOT(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount
                    [CTR176] = CTR:RP(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount

            Technical Business Rule Format:
                    (CountDocument('CGLS') = 1) AND (^CGLS34 > 0) AND (^CTR176 <> ^CGLS34)

        Data Elements:
            
                    RP(Instant):^CTR176 = tns:Capital.Losses.CarriedForward.Net.Amount
            
                    RP(Instant):^CGLS34 = CGLS:RP.TOT(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount
                    */
        protected void VRATOCTR428187(List<ProcessMessageDocument> response)
        {
            bool assertion = ChildDocument.CGLS34.GetValueOrDefault() > 0 &&
                             ChildDocument.CGLS34.GetValueOrDefault() != ParentDocument.CTR176.GetValueOrDefault();
            if (assertion)
            {
                var 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" } },
                };
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR176", Value = ParentDocument.CTR176.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGLS34", Value = ChildDocument.CGLS34.GetValueOrDefault().ToString() });
                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CTR.428187

        //CGLS-CTR

        #region VR.ATO.GEN.438000
        /*  VR.ATO.GEN.438000
            IF (period.startDate WHERE CONTEXT(ALL)) <> PARENT RETURN:RP:period.startDate
               RETURN VALIDATION MESSAGE
            ENDIF
              
        */
        private void VRATOGEN438000(List<ProcessMessageDocument> response)
        {
            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" } }
                              });
        }
        #endregion // VR.ATO.GEN.438000

        #region VR.ATO.GEN.438001
        /*  VR.ATO.CGTS.438001
            IF (period.endDate WHERE CONTEXT(ALL)) <> PARENT RETURN:RP:period.endDate
               RETURN VALIDATION MESSAGE
            ENDIF
        */
        private void VRATOGEN438001(List<ProcessMessageDocument> response)
        {
            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" } }
                              });
        }
        #endregion // VR.ATO.GEN.438001

        #region VR.ATO.GEN.402010
        /* VR.ATO.GEN.402010
            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

        */
        private void VRATOGEN402010(List<ProcessMessageDocument> response)
        {
            bool assertion = !string.IsNullOrWhiteSpace(ParentDocument.CTR11) &&
                             !string.IsNullOrWhiteSpace(ChildDocument.CGLS3) &&
                             !ParentDocument.CTR11.Equals(ChildDocument.CGLS3);
            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" } }
                };

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

        #region VR.ATO.GEN.402009
        /*
        
            IF RP:entity.identifier.TFN<> PARENT RETURN:RP:entity.identifier.TFN
               RETURN VALIDATION MESSAGE
            ENDIF
      */

        private void VRATOGEN402009(List<ProcessMessageDocument> response)
        {
            bool assertion = !ParentDocument.RPIdentifierTFN.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" } }
                };

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

        #region VR.ATO.GEN.428045
        /* VR.ATO.GEN.428045
            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
        */
        private void VRATOGEN428045(List<ProcessMessageDocument> response)
        {
            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)
            {
                var 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" } }
                };

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

        #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
                    
                    [CGLS107] = CGLS:RP.TOT:rvctc3.02.15:Tax.Losses.Deducted.Amount
                    [CTR117] = CTR:RP:rvctc2.02.00:IncomeTax.Deduction.TaxLossesDeducted.Amount

            Technical Business Rule Format:
                    ^CGLS107 > 0 AND    ^CGLS107 <>^CTR117

        Data Elements:
            
                    RP.TOT:^CGLS107 = tns:Tax.Losses.Deducted.Amount
            
                    RP.TOT:^CTR117 = CTR:RP:rvctc2.02.00:IncomeTax.Deduction.TaxLossesDeducted.Amount
                    */
        protected void VRATOCGLS404006(List<ProcessMessageDocument> response)
        {
            bool assertion = ChildDocument.CGLS107.GetValueOrDefault() > 0 &&
                ChildDocument.CGLS107.GetValueOrDefault() != ParentDocument.CTR117.GetValueOrDefault();

            if (assertion)
            {
                var 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 = "CTR117", Value = ParentDocument.CTR117.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGLS107", Value = ChildDocument.CGLS107.GetValueOrDefault().ToString() });

                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
                    
                    [CGLS19] = CGLS:RP.TOT:rvctc3.02.00:Tax.Losses.CarriedForward.Total.Amount
                    [CTR175] = CTR:RP:rvctc3.02.00:Tax.Losses.CarriedForward.Total.Amount

            Technical Business Rule Format:
                    ^CGLS19 > 0 AND    ^CGLS19 <> ^CTR175

        Data Elements:
            
                    RP.TOT:^CGLS19 = tns:Tax.Losses.CarriedForward.Total.Amount
            
                    RP.TOT:^CTR175 = CTR:RP:rvctc3.02.00:Tax.Losses.CarriedForward.Total.Amount
                    */
        protected void VRATOCGLS404011(List<ProcessMessageDocument> response)
        {
            bool assertion = ChildDocument.CGLS19.GetValueOrDefault() > 0 &&
           ChildDocument.CGLS19.GetValueOrDefault() != ParentDocument.CTR175.GetValueOrDefault();
            if (assertion)
            {
                var 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 = "CTR175", Value = ParentDocument.CTR175.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGLS19", Value = ChildDocument.CGLS19.GetValueOrDefault().ToString() });
                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CGLS.404011

        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;
        }
    }
}