using Ato.CD.Inbound.Shared;
using Ato.EN.IntegrationServices.CodeGenerationIEE;
using Ato.EN.IntegrationServices.CodeGenerationSMSFAR;
using VaTS;
using DataContracts;
using System.Collections.Generic;
using System.Linq;

namespace Ato.CD.Inbound.SMSFAR
{
    internal class CrossFormValidator
    {
        private SMSFAR2026 ParentDocument { get; }
        private BusinessDocumentCollection ChildDocuments { get; }

        private IEnumerable<IEE2021> IEE { get; }
     
        public CrossFormValidator(SMSFAR2026 report, BusinessDocumentCollection childDocuments)
        {
            ParentDocument = report;
            ChildDocuments = childDocuments ?? new BusinessDocumentCollection();
            IEE = ChildDocuments.Where(c => c.DocumentName.Equals("IEE")).Select(i => (IEE2021)i.ConsumedReport);
         
        }

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

            VRATOSMSFAR436038(response);
            VRATOSMSFAR436051(response);
            VRATOSMSFAR436127(response);
            VRATOSMSFAR436194(response);
            VRATOSMSFAR436197(response);
            VRATOSMSFAR436010(response);
            VRATOSMSFAR436196(response);
            VRATOSMSFAR436252(response);
            VRATOSMSFAR437194(response);
           

            return response;
        }

        #region VR.ATO.SMSFAR.436038
        /*  VR.ATO.SMSFAR.436038
            If Net capital gain is more than $10,000, a CGT schedule must be present

            Legacy Rule Format:
            IF [SMSFAR33] > 10000 AND  (COUNT(SCHEDULE = "CGTS") = 0)  
                RETURN VALIDATION MESSAGE
            ENDIF

            [SMSFAR33] = SMSFAR2019:RP:tns:Income.CapitalGainsNet.Amount

            Technical Business Rule Format:
            ^SMSFAR33 > 10000 AND  (CountDocument('CGTS') = 0)

            Data Elements:

            RP:^SMSFAR33 = tns:Income.CapitalGainsNet.Amount
        */
        private void VRATOSMSFAR436038(List<ProcessMessageDocument> response)
        {
            bool assertion = !ChildDocuments.Any(c => c.DocumentName.Equals(Schedule.CGTS.ToString())) &&
                             ParentDocument.SMSFAR33.HasValue && ParentDocument.SMSFAR33.Value > 10000;
            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.434034",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "If Net capital gain is more than $10,000, a CGT schedule must be present",
                    Location = "/xbrli:xbrl/tns:Income.CapitalGainsNet.Amount",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.436038" },
                        new ProcessMessageParameter { Name = "SMSFAR33", Value = ParentDocument.SMSFAR33.Value.ToString() }
                    }
                });
            }
        }
        #endregion

        #region VR.ATO.SMSFAR.436051
        /*  VR.ATO.SMSFAR.436051
            Payment summary schedule must be present when Payments where ABN not quoted amount is present

            Legacy Rule Format:
            IF [SMSFAR42] > 0 AND  AND (COUNT(SCHEDULE = "PSS") = 0) 
                RETURN VALIDATION MESSAGE
            ENDIF
                    
            [SMSFAR42] = SMSFAR2019:RP:tns:Remuneration.ABNNotQuotedPaymentGross.Amount

            Technical Business Rule Format:
            ^SMSFAR42 > 0 AND (CountDocument('PSS') = 0)

            Data Elements:
            
            RP:^SMSFAR42 = tns:Remuneration.ABNNotQuotedPaymentGross.Amount
        */
        private void VRATOSMSFAR436051(List<ProcessMessageDocument> response)
        {
            bool assertion = !ChildDocuments.Any(c => c.DocumentName.Equals(Schedule.PSS.ToString())) &&
                             ParentDocument.SMSFAR42.GetValueOrDefault() > 0;
            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.434044",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "Payment summary schedule must be present when Payments where ABN not quoted amount is present",
                    Location = "/xbrli:xbrl/tns:Remuneration.ABNNotQuotedPaymentGross.Amount",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.436051" },
                        new ProcessMessageParameter { Name = "SMSFAR42", Value = ParentDocument.SMSFAR42.GetValueOrDefault().ToString() }
                    }
                });
            }
        }
        #endregion

        #region VR.ATO.SMSFAR.436127
        /*  VR.ATO.SMSFAR.436127
            If the sum of 'Tax losses carried forward to later income years' and 'Net capital losses carried forward to later income years' is greater than $100000, a Losses schedule must be present

            Legacy Rule Format:
            IF ([SMSFAR85] + [SMSFAR380]) > 100000 AND (COUNT(SCHEDULE = "LS") = 0) 
                RETURN VALIDATION MESSAGE
            ENDIF
                    
            [SMSFAR85] = SMSFAR2019:RP.Closing:tns:Tax.Losses.CarriedForward.LaterIncomeYearsTotal.Amount
            [SMSFAR380] = SMSFAR2019:RP.Y0Plus.Closing(Instant):tns:Capital.Losses.CarriedForward.Net.Amount

            Technical Business Rule Format:
            (^SMSFAR85 + ^SMSFAR380) > 100000 AND (CountDocument('LS') = 0)

            Data Elements:
            
            RP.Closing:^SMSFAR85 = tns:Tax.Losses.CarriedForward.LaterIncomeYearsTotal.Amount
            
            RP.Y0Plus.Closing(Instant):^SMSFAR380 = tns:Capital.Losses.CarriedForward.Net.Amount
        */
        private void VRATOSMSFAR436127(List<ProcessMessageDocument> response)
        {
            bool assertion = !ChildDocuments.Any(c => c.DocumentName.Equals(Schedule.LS.ToString())) &&
                             ParentDocument.SMSFAR85.GetValueOrDefault() +
                             ParentDocument.SMSFAR380.GetValueOrDefault() > 100000;
            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.434085",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "Losses schedule must be attached if losses carried forward exceeds $100,000",
                    LongDescription = "If the sum of 'Tax losses carried forward to later income years' and 'Net capital losses carried forward to later income years' is greater than $100000, a Losses schedule must be present",
                    Location = "/xbrli:xbrl/tns:Tax.Losses.CarriedForward.LaterIncomeYearsTotal.Amount",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.436127" },
                        new ProcessMessageParameter { Name = "SMSFAR85", Value = ParentDocument.SMSFAR85.GetValueOrDefault().ToString() },
                        new ProcessMessageParameter { Name = "SMSFAR380", Value = ParentDocument.SMSFAR380.GetValueOrDefault().ToString() }
                    }
                });
            }
        }
        #endregion

        #region VR.ATO.SMSFAR.436194
        /*  VR.ATO.SMSFAR.436194
        Family Trust Election status code selected requires a Family trust election, revocation or variation schedule to be completed and attached to return and there is no schedule present.

        Legacy Rule Format:
        IF [SMSFAR163] = SET("R","V") AND  (COUNT(SCHEDULE = "FTER") = 0)
            RETURN VALIDATION MESSAGE
        ENDIF
                    
        [SMSFAR163] = SMSFAR2019:RP:tns:Elections.FamilyTrustElectionRevocation.Code

        Technical Business Rule Format:
        InSet(^SMSFAR163, '"R","V"') AND  (CountDocument('FTER') = 0)

        Data Elements:
            
        RP:^SMSFAR163 = tns:Elections.FamilyTrustElectionRevocation.Code
        */
        private void VRATOSMSFAR436194(List<ProcessMessageDocument> response)
        {
            bool assertion = !ChildDocuments.Any(c => c.DocumentName.Equals(Schedule.FTER.ToString())) &&
                             !string.IsNullOrWhiteSpace(ParentDocument.SMSFAR163) &&
                             new[] {"R", "V"}.Any(s => ParentDocument.SMSFAR163.ToUpper().Equals(s));
            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.432017",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "Family trust election or revocation schedule must be present",
                    Location = "/xbrli:xbrl/tns:Elections.FamilyTrustElectionRevocation.Code",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.436194" },
                        new ProcessMessageParameter { Name = "SMSFAR163", Value = ParentDocument.SMSFAR163 }
                    }
                });
            }
        }
        #endregion

        #region VR.ATO.SMSFAR.436197
        /*  VR.ATO.SMSFAR.436197
            The Interposed Entity Election code indicates a revocation is being made, however no schedule is attached.

            Legacy Rule Format:
            IF ([SMSFAR165] = "R") AND (COUNT(SCHEDULE = "IEE") = 0)
                RETURN VALIDATION MESSAGE
            ENDIF
                    
            [SMSFAR165] = SMSFAR2019:RP:tns:Elections.InterposedEntityElectionRevocation.Code

            Technical Business Rule Format:
            (^SMSFAR165 = 'R') AND (CountDocument('IEE') = 0)

            Data Elements:
            
            RP:^SMSFAR165 = tns:Elections.InterposedEntityElectionRevocation.Code
        */
        private void VRATOSMSFAR436197(List<ProcessMessageDocument> response)
        {
            bool assertion = !ChildDocuments.Any(c => c.DocumentName.Equals(Schedule.IEE.ToString())) &&
                             !string.IsNullOrWhiteSpace(ParentDocument.SMSFAR165) &&
                             ParentDocument.SMSFAR165.ToUpper().Equals("R");
            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.430180",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "If the Interposed Entity Election revocation code is present, an IEE schedule must be present",
                    Location = "/xbrli:xbrl/tns:Elections.InterposedEntityElectionRevocation.Code",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.436197" },
                        new ProcessMessageParameter { Name = "SMSFAR165", Value = ParentDocument.SMSFAR165 }
                    }
                });
            }
        }
        #endregion

        #region VR.ATO.SMSFAR.436010
        /*  VR.ATO.SMSFAR.436010
            The Family Trust TFN on the IEE must not be the same as the main entity TFN

            Legacy Rule Format:
            IF (COUNT(SCHEDULE = "IEE") > 0) AND RP:entity.identifier.TFN = (ANY OCCURRENCE OF([IEE50])) 
                RETURN VALIDATION MESSAGE
            ENDIF
                    
            [IEE50] = IEE:RP:tns:Identifiers.TaxFileNumber.Identifier IN TUPLE(tns:FamilyTrust)

            Technical Business Rule Format:
            (CountDocument('IEE') > 0) AND AnyOccurrence(^IEE50, ^IEE50 = ^TFN)

            Data Elements:
            ^IEE50 = IEE:RP:tns:Identifiers.TaxFileNumber.Identifier IN TUPLE(tns:FamilyTrust)
            ^TFN = RP
        */
        private void VRATOSMSFAR436010(List<ProcessMessageDocument> response)
        {
            bool assertion = IEE.Any(i => !string.IsNullOrWhiteSpace(i.IEE50) && i.IEE50.Equals(ParentDocument.RPIdentifierTFN));

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.430008",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "The Family Trust TFN on the IEE must not be the same as the main entity TFN",
                    LongDescription = "An Entity cannot interpose itself; therefore the family trust tax file number quoted in Interposed Entity Election cannot be the same as the tax file number of the entity making the election",
                    Location = "/xbrli:xbrl/xbrli:context",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.436010" } },
                });
            }
        }
        #endregion

        #region VR.ATO.SMSFAR.436196
        /*  VR.ATO.SMSFAR.436196
            If an IEE schedule is present, the Interposed entity election status - Specified income year must be present

            Legacy Rule Format:
            IF [SMSFAR164] = NULL and COUNT(SCHEDULE = "IEE") > 0
                RETURN VALIDATION MESSAGE
            ENDIF
                    
            [SMSFAR164] = SMSFAR2019:RP:tns:Elections.InterposedEntityElectionStatus.Year

            Technical Business Rule Format:
            ^SMSFAR164 = NULL and CountDocument('IEE') > 0

            Data Elements:
            RP:^SMSFAR164 = tns:Elections.InterposedEntityElectionStatus.Year
        */
        private void VRATOSMSFAR436196(List<ProcessMessageDocument> response)
        {
            bool assertion = IEE.Any() && !ParentDocument.SMSFAR164.HasValue;

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.430178",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "IEE specified income year must be present",
                    LongDescription = "If an IEE schedule is present, the Interposed entity election status - Specified income year must be present",
                    Location = "/xbrli:xbrl/tns:Elections.InterposedEntityElectionStatus.Year",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.436196" } }
                });
            }
        }
        #endregion

        #region VR.ATO.SMSFAR.436252
        /*  VR.ATO.SMSFAR.436252
            The income year for which the details of the Interposed Entity Election are being revoked must equal the income year of the main return being lodged.

            Legacy Rule Format:
            IF (SMSFAR2019:RP:tns:Report.TargetFinancial.Year <> NULL) AND (COUNT(SCHEDULE = "IEE") > 0) AND (ANY OCCURRENCE OF ([IEE116] = "R") AND ([IEE82] <> SMSFAR2019:RP:tns:Report.TargetFinancial.Year))
                    RETURN VALIDATION MESSAGE
            ENDIF
                    
            [IEE82] = IEE:RP:tns:Elections.Revocation.Year
            [IEE116] = IEE:RP:tns:Elections.InterposedEntityElectionOrRevocation.Code

            Technical Business Rule Format:
            (^SMSFAR1 <> NULL) AND (CountDocument('IEE') > 0) AND ((AnyOccurrence(^IEE116, ^IEE116 = 'R')) AND (^IEE82 <> ^SMSFAR1))

            Data Elements:
            
            RP:^SMSFAR1 = tns:Report.TargetFinancial.Year
            
            RP:^IEE82 = IEE:RP:rvctc3.66.66:Elections.Revocation.Year
            
            RP:^IEE116 = IEE:RP:rvctc3.66.66:Elections.InterposedEntityElectionOrRevocation.Code
        */
        private void VRATOSMSFAR436252(List<ProcessMessageDocument> response)
        {
            bool assertion = IEE.Any(i => i.IEE116.ToUpper().Equals("R") && i.IEE82.HasValue && i.IEE82 != ParentDocument.SMSFAR1);

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.430176",
                    Severity = ProcessMessageSeverity.Error,
                    Description = "Year of revocation must be the same as the year of the return",
                    LongDescription = "The income year for which the details of the Interposed Entity Election are being revoked must equal the income year of the main return being lodged.",
                    Location = "/xbrli:xbrl/tns:Report.TargetFinancial.Year",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.436252" },
                        new ProcessMessageParameter{ Name = "SMSFAR1", Value = ParentDocument.SMSFAR1.Value.ToString() }
                    }
                });
            }
        }
        #endregion

        #region VR.ATO.SMSFAR.437194
        /* VR.ATO.SMSFAR.437194
            Distributions to Beneficiaries of Trust schedule must be present when Gross distributions from trusts income is provided

            Legacy Rule Format:
            "IF COUNT(SCHEDULE = ""DISTBENTRT"") = 0 AND [SMSFAR47] > 0
                RETURN VALIDATION MESSAGE
            ENDIF"

            Technical Business Rule Format:
            !DISTBENTRTs.Any() && ParentDocument.SMSFAR47.GetValueOrDefault() > 0
        */
        protected void VRATOSMSFAR437194(List<ProcessMessageDocument> response)
        {
         
            bool assertion = !ChildDocuments.Any(c => c.DocumentName.Equals(Schedule.DISTBENTRT.ToString())) &&
                            ParentDocument.SMSFAR47.HasValue && ParentDocument.SMSFAR47.Value > 0;

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.SMSFAR.437194",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Distributions to Beneficiaries of Trust schedule must be present",
                    LongDescription = "Distributions to Beneficiaries of Trust schedule must be present when Gross distributions from trusts income is provided",
                    Location = "/xbrli:xbrl/tns:Income.TrustDistributionGross.Amount",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.SMSFAR.437194" },
                        new ProcessMessageParameter { Name = "SMSFAR47", Value = ParentDocument.SMSFAR47.HasValue ? ParentDocument.SMSFAR47.Value.ToString() : "null" }
                    }
                });
            }
        }
        #endregion

    }
}