using Ato.CD.Inbound.Shared;
using Ato.EN.IntegrationServices.CodeGenerationCGTS;
using Ato.EN.IntegrationServices.CodeGenerationDISTBENTRT;
using Ato.EN.IntegrationServices.CodeGenerationFITR;
using Ato.EN.IntegrationServices.CodeGenerationLS;
using Ato.EN.IntegrationServices.CodeGenerationPSS;
using DataContracts;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using VaTS;

namespace Ato.CD.Inbound.FITR202502
{
    internal class CrossFormValidator
    {
        private FITR2025 ParentDocument { get; }
        private BusinessDocumentCollection ChildDocuments { get; }
        private IEnumerable<CGTS2018> CGTSChildDocuments { get; set; }
        private IEnumerable<DISTBENTRT2024> DISTBENTRTChildDocuments { get; set; }
        private IEnumerable<LS2017> LSChildDocuments { get; set; }
        private IEnumerable<PSS2018> PSSChildDocuments { get; set; }

        public List<ProcessMessageDocument> Response { get; private set; }

        public CrossFormValidator(FITR2025 report, BusinessDocumentCollection childDocuments)
        {
            ParentDocument = report;
            ChildDocuments = childDocuments ?? new BusinessDocumentCollection();

            CGTSChildDocuments = ChildDocuments
                .Where(s => s.DocumentName.Equals(Schedule.CGTS.ToString()))
                .Select(p => (CGTS2018)p.ConsumedReport);

            DISTBENTRTChildDocuments = ChildDocuments
                .Where(s => s.DocumentName.Equals(Schedule.DISTBENTRT.ToString()))
                .Select(p => (DISTBENTRT2024)p.ConsumedReport);

            LSChildDocuments = ChildDocuments
                .Where(s => s.DocumentName.Equals(Schedule.LS.ToString()))
                .Select(p => (LS2017)p.ConsumedReport);

            PSSChildDocuments = ChildDocuments
                .Where(s => s.DocumentName.Equals(Schedule.PSS.ToString()))
                .Select(p => (PSS2018)p.ConsumedReport);

            Response = new List<ProcessMessageDocument>();
        }

        public List<ProcessMessageDocument> ValidateCrossFormRules()
        {
            VRATOFITR434034();
            VRATOFITR434085();
            VRATOFITR434300();
            VRATOFITR434614();
          
            return Response;
        }

        private bool ScheduledChildrenExists(string scheduledName)
        {
            return ChildDocuments.Any(docs => docs.DocumentName.Equals(scheduledName));
        }

        #region VR.ATO.FITR.434034

        /*  VR.ATO.FITR.434034
        If Net capital gain is more than $10,000, a CGT schedule must be present

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

        Data Elements:
        ^FITR23 = FITR:RP:Income.CapitalGainsNet.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFITR434034()
        {
            bool assertion = !ScheduledChildrenExists(Schedule.CGTS.ToString()) && ParentDocument.FITR23.HasValue && ParentDocument.FITR23.Value > 10000;
            if (assertion)
            {
                ProcessMessageDocument processMessage = 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 = "/tns:FITR/tns:RP/tns:Income/tns:CapitalGainsNetA",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FITR.434034" },
                        new ProcessMessageParameter { Name = "FITR23", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR23) }
                    }
                };

                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.FITR.434034

        #region VR.ATO.FITR.434085

        /*  VR.ATO.FITR.434085
        Losses schedule must be attached if losses carried forward exceeds $100,000

        Legacy Rule Format:
        IF ([FITR76] + [FITR207]) > 100000 AND (COUNT(SCHEDULE = "LS") = 0) 
            RETURN VALIDATION MESSAGE
        ENDIF

        Data Elements:
        ^FITR76 = FITR:RP:Tax.Losses.CarriedForward.LaterIncomeYearsTotal.Amount
        ^FITR207 = FITR:RP:Capital.Losses.CarriedForward.Net.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFITR434085()
        {
            bool assertion = ParentDocument.FITR76.GetValueOrDefault() + ParentDocument.FITR207.GetValueOrDefault() > 100000 && !ScheduledChildrenExists(Schedule.LS.ToString());

            if (assertion)
            {
                ProcessMessageDocument processMessage = 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 = "/tns:FITR/tns:RP/tns:Losses/tns:TaxCarriedForwardLaterIncomeYearsTotalA",
                    Parameters = new ProcessMessageParameters {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FITR.434085" },
                        new ProcessMessageParameter { Name = "FITR76", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR76) },
                        new ProcessMessageParameter { Name = "FITR207", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR207) }
                    }
                };

                Response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.FITR.434085

        #region VR.ATO.FITR.434300

        /*  VR.ATO.FITR.434300
        Payment summary schedule must be present when Payments where ABN not quoted amount is present

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

        Data Elements:
        ^FITR32 = FITR:RP:Remuneration.ABNNotQuotedPaymentGross.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFITR434300()
        {
            bool assertion = !ScheduledChildrenExists(Schedule.PSS.ToString()) && ParentDocument.FITR32.GetValueOrDefault() > 0;
            if (assertion)
            {
                ProcessMessageDocument processMessage = 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 = "/tns:FITR/tns:RP/tns:Income/tns:RemunerationABNNotQuotedPaymentGrossA",
                    Parameters = new ProcessMessageParameters {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FITR.434300" },
                        new ProcessMessageParameter { Name = "FITR32", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR32) }
                    }
                };

                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.FITR.434300

        #region VR.ATO.FITR.434614

        /*  VR.ATO.FITR.434614
        Distributions to Beneficiaries of Trust schedule must be present when the type of fund or trust is a Small APRA fund and Trust distributions - Income amounts or credits are provided

        Technical Business Rule:
        CountDocument('DISTBENTRT') = 0 AND ^FITR14 = '022' AND (^FITR37 > 0 OR ^FITR38 > 0 OR ^FITR39 > 0 OR ^FITR40 > 0)

        Data Elements:
        ^FITR14 = FITR:RP:Party.Type.Code
        ^FITR37 = FITR:RP:Income.TrustDistributionUnfranked.Amount
        ^FITR38 = FITR:RP:Income.TrustDistributionFranked.Amount
        ^FITR39 = FITR:RP:IncomeTax.FrankingCredits.FrankingCreditShareReceivedIndirectly.Amount
        ^FITR40 = FITR:RP:Income.TrustDistributionOther.Amount
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFITR434614()
        {
            bool assertion = !ScheduledChildrenExists(Schedule.DISTBENTRT.ToString()) && ParentDocument.FITR14.Equals("022") && (ParentDocument.FITR37.GetValueOrDefault() > 0 || ParentDocument.FITR38.GetValueOrDefault() > 0 || ParentDocument.FITR39.GetValueOrDefault() > 0 || ParentDocument.FITR40.GetValueOrDefault() > 0);

            if (assertion)
            {
                ProcessMessageDocument processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.FITR.434614",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Distributions to Beneficiaries of Trust schedule must be present",
                    LongDescription = @"Distributions to Beneficiaries of Trust schedule must be present when the type of fund or trust is a Small APRA fund and Trust distributions - Income amounts or credits are provided",
                    Location = "/tns:FITR/tns:RP/tns:StatusOfFundOrTrust/tns:PartyTypeC",
                    Parameters = new ProcessMessageParameters {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FITR.434614" },
                        new ProcessMessageParameter { Name = "FITR14", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR14) },
                        new ProcessMessageParameter { Name = "FITR37", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR37) },
                        new ProcessMessageParameter { Name = "FITR38", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR38) },
                        new ProcessMessageParameter { Name = "FITR39", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR39) },
                        new ProcessMessageParameter { Name = "FITR40", Value = FITR2025Validator.GetValueOrEmpty(ParentDocument.FITR40) }
                    }
                };

                Response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.FITR.434614
    }
}