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

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

        private LS2017 ChildDocument { get; }

        private List<Context> Contexts { get; }

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

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

            VRATOCTR428102(response);
            VRATOCTR428190(response);
            VRATOCTR428191(response);
            VRATOGEN402009(response);
            VRATOGEN402010(response);
            VRATOGEN438000(response);
            VRATOGEN438001(response);
            VRATOGEN428045(response);
            VRATOLS414023(response);

            return response;
        }

        #region VR.ATO.CTR.428102
        /*  VR.ATO.CTR.428102
          

            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

            [CTR53] = CTR:RP:pyde.02.03:OrganisationDetails.TaxConsolidationStatus.Code
            [CTR117] = CTR:RP:rvctc2.02.00:IncomeTax.Deduction.TaxLossesDeducted.Amount
            [LS15] = LS:RP.Y0:rvctc3.02.00:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
            [LS16] = LS:RP.Y0-1:rvctc3.02.00:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
            [LS17] = LS:RP.Y0-2:rvctc3.02.00:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
            [LS18] = LS:RP.Y0-3:rvctc3.02.00:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
            [LS19] = LS:RP.Y0-4:rvctc3.02.00:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator
            [LS53] = LS:RP.Y0-5P:rvctc3.02.00:Tax.Losses.CarriedForward.ContinuityOfMajorityOwnershipTestPassed.Indicator

                    */
        private void VRATOCTR428102(List<ProcessMessageDocument> response)
        {
            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)
            {
                var 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" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR117", Value = ParentDocument.CTR117.GetValueOrDefault().ToString() });


                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.SMSFAR.436801

        #region VR.ATO.CTR.428190
        /*  VR.ATO.CTR.428190
                          IF (COUNT(SCHEDULE = "LS") = 1) AND 
                ([CTR175] <> [LS50]) 
                   RETURN VALIDATION MESSAGE
                ENDIF

                [CTR175] = CTR:RP:rvctc3.02.00:Tax.Losses.CarriedForward.Total.Amount
                [LS50] = LS:RP.ALL:rvctc3.02.00:Tax.Losses.CarriedForward.Total.Amount

                    */
        private void VRATOCTR428190(List<ProcessMessageDocument> response)
        {
            bool assertion = ParentDocument.CTR175.GetValueOrDefault() != ChildDocument.LS50.GetValueOrDefault();

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

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

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CTR.428190

        #region VR.ATO.CTR.428191
        /*  VR.ATO.CTR.428191
            IF (COUNT(SCHEDULE = "LS") = 1) AND ([CTR176] <> [LS52]) 
               RETURN VALIDATION MESSAGE
            ENDIF

            [CTR176] = CTR:RP(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount
            [LS52] = LS:RP.ALL(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount

                    */
        private void VRATOCTR428191(List<ProcessMessageDocument> response)
        {
            bool assertion = ParentDocument.CTR176.GetValueOrDefault() != ChildDocument.LS52.GetValueOrDefault();

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

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

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CTR.428191

        #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.402010
        /* VR.ATO.GEN.402009
            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.LS3) &&
                             !ParentDocument.CTR11.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" } }
                };

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

        #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.GEN.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.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.LS2) &&
                             !ParentDocument.CTR9.ToUpper().Equals(ChildDocument.LS2.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.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
                    
                    [LS25] = LS:RP:rvctc3.02.00:Tax.Losses.ChangeOfOwnershipOrControlAfterReferenceTime.Indicator

            Technical Business Rule Format:
                    (ParentDocument('CTR')) AND ^LS25 = NULL

        Data Elements:
            
                    RP:^LS25 = tns:Tax.Losses.ChangeOfOwnershipOrControlAfterReferenceTime.Indicator
                    */
        private void VRATOLS414023(List<ProcessMessageDocument> response)
        {
            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" } }
                };
                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.LS.414023

        private List<Context> GetContexts() => new List<Context>()
            .AddContext(ChildDocument.RPStartDate, ChildDocument.RPEndDate, ChildDocument.RPOccurrenceIndex, ChildDocument.RPId)
            .AddContext(ChildDocument.RPY0StartDate, ChildDocument.RPY0EndDate, ChildDocument.RPY0OccurrenceIndex, ChildDocument.RPY0Id)
            .AddContext(ChildDocument.RPY0Minus1StartDate, ChildDocument.RPY0Minus1EndDate, ChildDocument.RPY0Minus1OccurrenceIndex, ChildDocument.RPY0Minus1Id)
            .AddContext(ChildDocument.RPY0Minus2StartDate, ChildDocument.RPY0Minus2EndDate, ChildDocument.RPY0Minus2OccurrenceIndex, ChildDocument.RPY0Minus2Id)
            .AddContext(ChildDocument.RPY0Minus3StartDate, ChildDocument.RPY0Minus3EndDate, ChildDocument.RPY0Minus3OccurrenceIndex, ChildDocument.RPY0Minus3Id)
            .AddContext(ChildDocument.RPY0Minus4StartDate, ChildDocument.RPY0Minus4EndDate, ChildDocument.RPY0Minus4OccurrenceIndex, ChildDocument.RPY0Minus4Id)
            .AddContext(ChildDocument.RPY0Minus5PStartDate, ChildDocument.RPY0Minus5PEndDate, ChildDocument.RPY0Minus5POccurrenceIndex, ChildDocument.RPY0Minus5PId)
            .AddContext(ChildDocument.RPALLStartDate, ChildDocument.RPALLEndDate, ChildDocument.RPALLOccurrenceIndex, ChildDocument.RPALLId);
    }
}