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


namespace Ato.CD.Inbound.CTR202502
{
    internal class CrossFormValidatorRDTIS : ICrossFormValidator
    {
        private CTR2025 ParentDocument { get; }
        private RDTIS2023 ChildDocument { get; }
        static int expenditureCap = Int32.Parse("150,000,000", System.Globalization.NumberStyles.Number); //ExpenditureCap = $150 million, Constant Tab in VR Artefacts;
        static decimal refundablePremium = 0.185M; //18.5%, Constant Tab in VR Artefacts;

        internal CrossFormValidatorRDTIS(CTR2025 report, BusinessDocument childDocument)
        {
            ParentDocument = report;
            RDTIS2023XmlConsumer consumer = new RDTIS2023XmlConsumer();
            childDocument.DocumentStream.Position = 0;
            ChildDocument = consumer.Consume(childDocument.DocumentStream, true);
        }

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

            VRATOGEN402009(response);
            VRATOIEE438104(response);
            VRATOCTR500332(response);
            VRATOCTR500333(response);
            VRATOCTRW00028(response);

            return response;
        }


        //RTDIS_CTR
        #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.RDTIS70);


            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 = "/tns:RDTIS/tns:RP/tns:TaxFileNumberId",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.402009" } }
                };
                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.GEN.402009

        #region  VR.ATO.RDTIS.438104
        /*  
             VR.ATO.RDTIS.438104
        (^RDTIS71 <> PARENT PERIOD START DATE) OR (^RDTIS72 <> PARENT PERIOD END DATE)

         */
        protected void VRATOIEE438104(List<ProcessMessageDocument> response)
        {
            ProcessMessageDocument processMessage;
            bool assertion = ((ChildDocument.RDTIS71.HasValue && ChildDocument.RDTIS71 != ParentDocument.RPStartDate) || ChildDocument.RDTIS72.HasValue && ChildDocument.RDTIS72 != ParentDocument.RPEndDate);

            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.RDTIS.438104",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Reporting period does not match the reporting period supplied on the form it was submitted with",
                    Location = "/tns:RDTIS/tns:RP/tns:PeriodStartD",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.RDTIS.438104" } },
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS71", Value = ChildDocument.RDTIS71.ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS72", Value = ChildDocument.RDTIS72.ToString() });
                response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.GEN.438000

        #region VR.ATO.CTR.500332 
        /*  VR.ATO.CTR.500332 //Old rule: VR.ATO.RDTIS.438114
        
        Refundable R&D tax offset calculated value is incorrect

        Technical Business Rule Format:
        IF [RDTIS36] = FALSE AND [RDTIS37] = FALSE AND [RDTIS46] > 0 AND [RDTIS46] <> (RefundableOffsetCalc() +/- 1)
            RETURN VALIDATION MESSAGE
        ENDIF
        
        Data Elements:
            ^RDTIS36 = RDTIS:RP:AggregatedTurnover:TaxConcession.ExemptEntityOwnership.Indicator
            ^RDTIS37 = RDTIS:RP:AggregatedTurnover:TaxConcession.AggregatedTurnoverAtOrAboveThreshold.Indicator
            ^RDTIS46 = RDTIS:RP:RefundableTaxOffset:TaxConcession.ResearchAndDevelopment.TaxOffsetRefundable.Amount
        */
        public void VRATOCTR500332(List<ProcessMessageDocument> response)
        {
            ProcessMessageDocument processMessage;
            Decimal refundableOffset = 0;
            bool assertion = false;
            if (ChildDocument.RDTIS36 != null && ChildDocument.RDTIS36 == false &&
                 ChildDocument.RDTIS37 != null && ChildDocument.RDTIS37 == false &&
                 ChildDocument.RDTIS46 != null && ChildDocument.RDTIS46.GetValueOrDefault() > 0)
            {
                refundableOffset = CalcRefundableOffset(ChildDocument, true);
                assertion = OutsideRange(ChildDocument.RDTIS46.GetValueOrDefault(), refundableOffset, 1); // Get RefundableOffset
            }
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.CTR.500332",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Refundable R&D tax offset calculated value is incorrect",
                    Location = "/tns:RDTIS/tns:RP/tns:RefundableTaxOffset/tns:TaxConcessionResearchAndDevelopmentTaxOffsetRefundableA",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.CTR.500332" } },
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS36", Value = ChildDocument.RDTIS36.ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS37", Value = ChildDocument.RDTIS37.ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS46", Value = GetValueOrEmpty(ChildDocument.RDTIS46) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "Calculated Refundable R&D Tax Offset", Value = refundableOffset.ToString() });
                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CTR.500332

        #region VR.ATO.CTR.500333
        /*  VR.ATO.CTR.500333  //VR.ATO.CTR.438115
            Non-refundable R&D tax offset calculated value is incorrect

            Technical Business Rule Format:
                IF [RDTIS36] = TRUE OR [RDTIS37] = TRUE) AND [RDTIS48] > 0 AND [RDTIS48] <> (NonRefundableOffsetCalc() +/- 1)
                    RETURN VALIDATION MESSAGE
                ENDIF
            
            Data Elements:
                ^RDTIS36 = RDTIS:RP:AggregatedTurnover:TaxConcession.ExemptEntityOwnership.Indicator
                ^RDTIS37 = RDTIS:RP:AggregatedTurnover:TaxConcession.AggregatedTurnoverAtOrAboveThreshold.Indicator
                ^RDTIS48 = RDTIS:RP:NonRefundableTaxOffset:TaxConcession.ResearchAndDevelopment.TaxOffsetNonRefundable.Amount
         */
        public void VRATOCTR500333(List<ProcessMessageDocument> response)
        {
            ProcessMessageDocument processMessage;
            decimal NonRefundableOffset = 0;
            bool assertion = false;
            if ((ChildDocument.RDTIS36 != null && ChildDocument.RDTIS36 == true ||
                  ChildDocument.RDTIS37 != null && ChildDocument.RDTIS37 == true) &&
                 (ChildDocument.RDTIS48 != null && ChildDocument.RDTIS48.GetValueOrDefault() > 0))
            {
                NonRefundableOffset = calcNonRefundableOffset(ChildDocument);
                assertion = OutsideRange(ChildDocument.RDTIS48.GetValueOrDefault(), NonRefundableOffset, 1);
            }
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.CTR.500333",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Non-refundable R&D tax offset calculated value is incorrect",
                    Location = "/tns:RDTIS/tns:RP/tns:NonRefundableTaxOffset/tns:TaxConcessionResearchAndDevelopmentTaxOffsetNonRefundableA",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.CTR.500333" } },
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS36", Value = ChildDocument.RDTIS36.ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS37", Value = ChildDocument.RDTIS37.ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS48", Value = GetValueOrEmpty(ChildDocument.RDTIS48) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "Calculated Non-refundable R&D Tax Offset", Value = NonRefundableOffset.ToString() });
                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CTR.500333

        private static string GetValueOrEmpty(decimal? val)
        {
            return (val.HasValue) ? val.ToString() : string.Empty;
        }

        private static bool OutsideRange(decimal field, decimal expression, int range)
        {
            bool response;

            response = (field < (expression - range)) || (field > (expression + range));

            return response;
        }

        #region CalcRefundableOffset

        /*
        IF ([RDTIS45] < ExpenditureCap) THEN
             [RDTIS45] * ([RDTIS78] + RefundablePremium)
        ELSE 
             (ExpenditureCap * ([RDTIS78] + RefundablePremium)) + (([RDTIS45] - ExpenditureCap) * [RDTIS78])
        ENDIF
        */
        private decimal CalcRefundableOffset(RDTIS2023 report, bool isRefundableOffset)
        {
            if (ChildDocument.RDTIS45 < expenditureCap)
            {
                return (decimal)(ChildDocument.RDTIS45.GetValueOrDefault() * ((ChildDocument.RDTIS78.GetValueOrDefault() / 100) + refundablePremium));
            }
            else
            {
                return (decimal)((expenditureCap * ((ChildDocument.RDTIS78.GetValueOrDefault() / 100) + refundablePremium)) + ((ChildDocument.RDTIS45.GetValueOrDefault() - expenditureCap) * (ChildDocument.RDTIS78.GetValueOrDefault() / 100)));
            }
        }

        #endregion

        #region calcNonRefundableOffset

        /*
         IF ([RDTIS47] > ExpenditureCap AND [RDTIS81] = 0)  THEN
            Intensity = 100
            ExcessOffset = ([RDTIS47] - ExpenditureCap) * [RDTIS78]
     
        ELSE IF [RDTIS81] = 0 THEN
            Intensity = 100
            ExcessOffset = 0          
     
        ELSE IF ([RDTIS47] > ExpenditureCap) THEN
            Intensity = (ExpenditureCap / [RDTIS81])
            ExcessOffset = ([RDTIS47] - ExpenditureCap) * [RDTIS78]
     
        ELSE
            Intensity = ([RDTIS47] / [RDTIS81])
            ExcessOffset = 0
     
        ENDIF             
           
            IF (Intensity > 0 AND Intensity <= T1Intensity) THEN
                 IF ([RDTIS47] > ExpenditureCap) THEN
                      T1Deductions = ExpenditureCap
                 ELSE
                      T1Deductions = [RDTIS47]
                 ENDIF
            ELSE
                 T1Deductions = T1Intensity * [RDTIS81]
                      IF [RDTIS47] > ExpenditureCap THEN
                           T2Deductions = (ExpenditureCap - T1Deductions)
                      ELSE
                           T2Deductions = ([RDTIS47] - T1Deductions)
                      ENDIF
            ENDIF

            T1Offset = (T1Deductions * ([RDTIS78] + T1Premium))
            T2Offset = (T2Deductions * ([RDTIS78] + T2Premium))

            NonRefundableOffset = T1Offset + T2Offset + ExcessOffset

         */
        private decimal calcNonRefundableOffset(RDTIS2023 report)
        {
            decimal intensity = 0, excessOffset = 0;
            // T1,T2  Deduction Calculation Variable
            decimal t1Intensity = 0.02M; // 2%;
            //decimal t2Intensity = 0.02+M; // 2+% ;  
            decimal t1Deductions = 0, t2Deductions = 0;
            // Premium %
            decimal t1Premium = 0.085M; // 8.5%;
            decimal t2Premium = 0.165M; // 16.5%;

            //decimal taxRate = (ChildDocument.RDTIS78.GetValueOrDefault() / 100); //RDTIS78

            // intensity and excessOffset Calculation            
            if (ChildDocument.RDTIS47.GetValueOrDefault() > expenditureCap && ChildDocument.RDTIS81.GetValueOrDefault() == 0)
            {
                intensity = 100;
                excessOffset = (ChildDocument.RDTIS47.GetValueOrDefault() - expenditureCap) * (ChildDocument.RDTIS78.GetValueOrDefault() / 100);
            }
            else if (ChildDocument.RDTIS81.GetValueOrDefault() == 0)
            {
                intensity = 100;
                excessOffset = 0;

            }
            else if (ChildDocument.RDTIS47.GetValueOrDefault() > expenditureCap)
            {
                intensity = (expenditureCap / ChildDocument.RDTIS81.GetValueOrDefault());
                excessOffset = (ChildDocument.RDTIS47.GetValueOrDefault() - expenditureCap) * (ChildDocument.RDTIS78.GetValueOrDefault() / 100);
            }
            else
            {
                intensity = (ChildDocument.RDTIS47.GetValueOrDefault() / ChildDocument.RDTIS81.GetValueOrDefault());
                excessOffset = 0;
            }

            // T1,T2 Deduction Calculation             
            if (intensity > 0 && intensity <= t1Intensity) // Tier1 deduction
            {
                t1Deductions = ChildDocument.RDTIS47.GetValueOrDefault() > expenditureCap ? expenditureCap : ChildDocument.RDTIS47.GetValueOrDefault();
            }
            else
            {
                t1Deductions = t1Intensity * ChildDocument.RDTIS81.GetValueOrDefault();
                //IF[RDTIS47] > ExpenditureCap THEN
                //         T2Deductions = (ExpenditureCap - T1Deductions)
                //      ELSE
                //           T2Deductions = ([RDTIS47] - T1Deductions)
                //      ENDIF
                //if (intensity > t1Intensity )//&& intensity <= t2Intensity) // Tier2 deduction
                //{
                t2Deductions = ChildDocument.RDTIS47.GetValueOrDefault() > expenditureCap ? (expenditureCap - t1Deductions) : (ChildDocument.RDTIS47.GetValueOrDefault() - t1Deductions);
                //}
                //else
                //{
                //    t2Deductions = (t2Intensity * ChildDocument.RDTIS81.GetValueOrDefault()) - t1Deductions;

                //}
            }
            // t1Offset + t2Offset + excessOffset  
            return Math.Round(((t1Deductions * ((ChildDocument.RDTIS78.GetValueOrDefault() / 100) + t1Premium)) + (t2Deductions * ((ChildDocument.RDTIS78.GetValueOrDefault() / 100) + t2Premium)) + excessOffset), 2, MidpointRounding.AwayFromZero);
        }

        #endregion

        #region VR.ATO.CTR.W00028

        /*  VR.ATO.CTR.W00028
                    We use information in this form to meet our obligation to publish R&D expenditure companies claim. This will include publishing your company name, ABN or ACN and claim for notional deductions. For more information, see ato.gov.au

                Legacy Rule Format:
                    IF (COUNT(SCHEDULE = "RDTIS") = 1) AND [RDTIS24] <> NULL OR [RDTIS73] <> NULL
                       RETURN VALIDATION MESSAGE
                    ENDIF

            Technical Business Rule Format:
                    (CountDocument('RDTIS') = 1) AND ^RDTIS24 <> NULL OR ^RDTIS73 <> NULL

            Data Elements:

                ^RDTIS24 = RDTIS24

                ^RDTIS73 = RDTIS73
        */
        public void VRATOCTRW00028(List<ProcessMessageDocument> response)
        {
            ProcessMessageDocument processMessage;
            bool assertion = ChildDocument.RDTIS24 != null || ChildDocument.RDTIS73 != null;
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.CTR.W00028",
                    Severity = ProcessMessageSeverity.Warning,
                    Description = @"We use information in this form to meet our obligation to publish R&D expenditure companies claim. This will include publishing your company name, ABN or ACN and claim for notional deductions less feedstock adjustments. For more information, see ato.gov.au/RDTI",
                    Location = "/xbrli:xbrl/tns:Report.TargetFinancial.Year", //CTR2
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.CTR.W00028" } },
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS24", Value = GetValueOrEmpty(ChildDocument.RDTIS24) });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "RDTIS73", Value = GetValueOrEmpty(ChildDocument.RDTIS73) });

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