using Ato.CD.Inbound.Shared;
using Ato.EN.IntegrationServices.CodeGenerationFTER;
using Ato.EN.IntegrationServices.CodeGenerationTRT;
using DataContracts;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace Ato.CD.Inbound.TRT
{
    public class CrossFormValidatorFTER : ICrossFormValidator
    {
        private FTER2021 childDocument { get; set; }
        
        public List<ProcessMessageDocument> response { get; private set; }

        private TRT2026 parentDocument { get; set; }

        public CrossFormValidatorFTER(TRT2026 parent, object child)
        {
            childDocument = (FTER2021)child;
            parentDocument = parent;
            response = new List<ProcessMessageDocument>();
        }

        public List<ProcessMessageDocument> ValidateCrossFormRules()
        {
            VRATOFTER408001();
            VRATOFTER408029();
            VRATOFTER408033();
            VRATOFTER408112();
            VRATOFTER408162();
            VRATOFTER408205();
            VRATOFTER408371();
            VRATOFTER408372();

            return response;
        }

        #region Validation Rules

        #region VR.ATO.FTER.408001

        /*  VR.ATO.FTER.408001
        TFN on Schedule must match TFN on main form
    
        Legacy Rule Format:
        WHERE PARENT RETURN EXISTS 
        IF (FTER:RP:entity.identifier.TFN <> NULLORBLANK) AND (FTER:RP:entity.identifier.TFN <> PARENT RETURN:RP:entity.identifier.TFN)
            RETURN VALIDATION MESSAGE
        ENDIF
    
        Technical Business Rule Format:
        (^TFN <> BLANK) AND (^TFN <> ^ParentTFN)
    
        Data Elements:

        ^ParentTFN = ParentTFN

        ^TFN = RP
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFTER408001()
        {
            bool assertion = !string.IsNullOrWhiteSpace(childDocument.FTER3) && !string.IsNullOrWhiteSpace(parentDocument.TRT5) && !childDocument.FTER3.Equals(parentDocument.TRT5);

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.410115",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"TFN on Schedule must match TFN on main form",
                    Location = "/tns:FTER/tns:RP/tns:TaxFileNumberId",
                    Parameters = new ProcessMessageParameters {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FTER.408001" },
                        new ProcessMessageParameter { Name = "FTER3", Value = childDocument.FTER3 },
                        new ProcessMessageParameter { Name = "TRT5", Value = parentDocument.TRT5 }
                    }
                });
            }
        }

        #endregion // VR.ATO.FTER.408001

        #region VR.ATO.FTER.408029

        /*  VR.ATO.FTER.408029
        Income year for variation must match the year of return on the main form

        Legacy Rule Format:
        WHERE PARENT RETURN EXISTS
        IF [FTER95] = "V" AND [FTER40] <> NULL AND [FTER40] <> PARENT RETURN:RP:pyin.xx.xx:Report.TargetFinancial.Year
            RETURN VALIDATION MESSAGE
        ENDIF

        [FTER95] = FTER:RP:Elections.FamilyTrustElectionRevocation.Code
        [FTER40] = FTER:RP:Elections.FamilyTrustElectionStatus.Year

        Technical Business Rule Format:
        ^FTER95 = 'V' AND ^FTER40 <> NULL AND ^FTER40 <> ^ParentTargetFinancialYear

        Data Elements:

        RP:^FTER40 = tns:ElectionsFamilyTrustElectionStatusY
                
        RP:^FTER95 = tns:ElectionsFamilyTrustElectionRevocationC
                
        RP:^ParentTargetFinancialYear = ParentTargetFinancialYear
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFTER408029()
        {
            bool assertion = childDocument.FTER95 == @"V" && childDocument.FTER40.HasValue && !childDocument.FTER40.GetValueOrDefault().Equals(parentDocument.TRT1.GetValueOrDefault());

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.FTER.408029",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Income year for variation must match the year of return on the main form",
                    LongDescription = @"Income year specified for the purpose of the FTE variation must match the year of return on the main form",
                    Location = "/tns:FTER/tns:RP/tns:ElectionOrVariationIncomeYear/tns:ElectionsFamilyTrustElectionStatusY",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FTER.408029" },
                        new ProcessMessageParameter { Name = "FTER95", Value = childDocument.FTER95 },
                        new ProcessMessageParameter { Name = "FTER40", Value = childDocument.FTER40.GetValueOrDefault().ToString() },
                        new ProcessMessageParameter { Name = "TRT1", Value = parentDocument.TRT1.GetValueOrDefault().ToString() }
                    }
                });
            }
        }

        #endregion // VR.ATO.FTER.408029

        #region VR.ATO.FTER.408033

        /*  VR.ATO.FTER.408033
        Revocation indicated and income year of revocation not the same as year of return

        Legacy Rule Format:
        IF [FTER95] = "R" AND [FTER96] <> NULL AND [FTER96] <> PARENT RETURN:RP:pyin.xx.xx:Report.TargetFinancial.Year
            RETURN VALIDATION MESSAGE
        ENDIF

        [FTER95] = FTER:RP:Elections.FamilyTrustElectionRevocation.Code
        [FTER96] = FTER:RP:Elections.FamilyTrustRevocationStatusEffective.Year

        Technical Business Rule Format:
        ^FTER95 = 'R' AND ^FTER96 <> NULL AND ^FTER96 <> ^ParentTargetFinancialYear

        Data Elements:

        RP:^FTER96 = tns:ElectionsStatusEffectiveY

        RP:^FTER95 = tns:ElectionsFamilyTrustElectionRevocationC

        RP:^ParentTargetFinancialYear = ParentTargetFinancialYear
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFTER408033()
        {
            bool assertion = childDocument.FTER95 == @"R" && childDocument.FTER96.HasValue && !childDocument.FTER96.GetValueOrDefault().Equals(parentDocument.TRT1.GetValueOrDefault());

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.FTER.408390",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Income year of revocation must be the same as the year of return on the main form",
                    Location = "/tns:FTER/tns:RP/tns:FamilyTrustRevocation/tns:ElectionsStatusEffectiveY",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FTER.408033" },
                        new ProcessMessageParameter { Name = "FTER95", Value = childDocument.FTER95 },
                        new ProcessMessageParameter { Name = "FTER96", Value = childDocument.FTER96.GetValueOrDefault().ToString() },
                        new ProcessMessageParameter { Name = "TRT1", Value = parentDocument.TRT1.GetValueOrDefault().ToString() }
                    }
                });
            }
        }

        #endregion // VR.ATO.FTER.408033

        #region VR.ATO.FTER.408112

        /*  VR.ATO.FTER.408112
        Income year specified on main return form must equal the income year specified on the FTE schedule.

        Legacy Rule Format:
        WHERE PARENT RETURN EXISTS
        IF [FTER95] = "E" AND [FTER40] <>  PARENT RETURN:RP:Elections.FamilyTrustElectionStatus.Year
            RETURN VALIDATION MESSAGE
        ENDIF

        [FTER95] = FTER:RP:Elections.FamilyTrustElectionRevocation.Code
        [FTER40] = FTER:RP:Elections.FamilyTrustElectionStatus.Year

        Technical Business Rule Format:
        ^FTER95 = 'E' AND ^FTER40 <> ^ParentFamilyTrustElectionStatusYear

        Data Elements:
                
        RP:^FTER40 = tns:ElectionsFamilyTrustElectionStatusY
                
        RP:^FTER95 = tns:ElectionsFamilyTrustElectionRevocationC
                
        RP:^ParentFamilyTrustElectionStatusYear = ParentFamilyTrustElectionStatusYear
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFTER408112()
        {
            bool assertion = childDocument.FTER95 == @"E" && childDocument.FTER40.HasValue && !childDocument.FTER40.GetValueOrDefault().Equals(parentDocument.TRT28.GetValueOrDefault());

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.FTER.408377",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Income year specified on main return form must equal the income year specified on the schedule",
                    Location = "/tns:FTER/tns:RP/tns:ElectionOrVariationIncomeYear/tns:ElectionsFamilyTrustElectionStatusY",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FTER.408112" },
                        new ProcessMessageParameter { Name = "FTER95", Value = childDocument.FTER95 },
                        new ProcessMessageParameter { Name = "FTER40", Value = childDocument.FTER40.GetValueOrDefault().ToString() },
                        new ProcessMessageParameter { Name = "TRT28", Value = parentDocument.TRT28.GetValueOrDefault().ToString() }
                    }
                });
            }
        }

        #endregion // VR.ATO.FTER.408112

        #region VR.ATO.FTER.408162

        /*  VR.ATO.FTER.408162
        Revocation date must not be after 30 June of the year of the parent return

        Legacy Rule Format:
        WHERE PARENT RETURN EXISTS
        IF [FTER57] > ((PARENT RETURN:RP:pyin.xx.xx:Report.TargetFinancial.Year)&"-06-30")
            RETURN VALIDATION MESSAGE 
        ENDIF

        [FTER57] = FTER:RP:Elections.Revocation.Date

        Technical Business Rule Format:
        ^FTER57 > AsDate(Concat(^ParentTargetFinancialYear, '-06-30'))

        Data Elements:

        RP:^FTER57 = tns:Elections.Revocation.Date

        RP:^ParentTargetFinancialYear = ParentTargetFinancialYear
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFTER408162()
        {
            bool assertion = childDocument.FTER57.GetValueOrDefault() > AsDate(string.Concat(parentDocument.TRT1.GetValueOrDefault(), @"-06-30"));

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.FTER.408389",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Revocation date must not be after 30 June of the year of return on the main form",
                    Location = "/tns:FTER/tns:RP/tns:FamilyTrustRevocation/tns:ElectionsD",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FTER.408162" },
                        new ProcessMessageParameter { Name = "FTER57", Value =  TRT2026Validator.GetValueOrEmptyDate(childDocument.FTER57) },
                        new ProcessMessageParameter { Name = "TRT1", Value =  parentDocument.TRT1.GetValueOrDefault().ToString ()}
                    }
                });
            }
        }

        #endregion // VR.ATO.FTER.408162

        #region VR.ATO.FTER.408205

        /*  VR.ATO.FTER.408205
        Your supplied ABN does not match the ABN supplied on the form it was submitted with

        Legacy Rule Format:
        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

        Technical Business Rule Format:
        (^FTER170 <> BLANK) AND (^ParentABN <> BLANK) AND (^FTER170 <> ^ParentABN)

        Data Elements:

        RP:^FTER170 = tns:Identifiers.AustralianBusinessNumber.Identifier

        RP:^ParentABN = ParentABN
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFTER408205()
        {
            bool assertion = !string.IsNullOrWhiteSpace(childDocument.FTER170) && !string.IsNullOrWhiteSpace(parentDocument.TRT7) && !childDocument.FTER170.Equals(parentDocument.TRT7);

            if (assertion)
            {
                response.Add(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 = "/tns:FTER/tns:RP/tns:AustralianBusinessNumberId",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FTER.408205" },
                        new ProcessMessageParameter { Name = "FTER170", Value = childDocument.FTER170 },
                        new ProcessMessageParameter { Name = "TRT7", Value = parentDocument.TRT7 }
                    }
                });
            }
        }

        #endregion // VR.ATO.GEN.402010 

        #region VR.ATO.FTER.408371

        /*  VR.ATO.FTER.408371
        Reporting period start date must match the period start date on the main form
        
        Technical Business Rule Format:
        WHERE PARENT RETURN EXISTS
        ^FTER173 <> ^ParentPeriodStartDate

        Data Elements:

        RP:^FTER173 = tns:Period.Start.Date

        RP:^ParentPeriodStartDate = ParentPeriodStartDate
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFTER408371()
        {
            bool assertion = parentDocument.TRT573.Value != childDocument.FTER173.Value;

            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.FTER.408371",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Reporting period start date must match the period start date on the main form",
                    Location = "/tns:FTER/tns:RP/tns:PeriodStartD",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FTER.408371" },
                        new ProcessMessageParameter { Name = "FTER173", Value = childDocument.FTER173.Value.ToString("yyyy-MM-dd") },
                        new ProcessMessageParameter { Name = "TRT573", Value = parentDocument.TRT573.Value.ToString("yyyy-MM-dd") }
                    }
                });
            }
        }

        #endregion // VR.ATO.FTER.408371 

        #region VR.ATO.FTER.408372

        /*  VR.ATO.FTER.408372
        Reporting period end date must match the period end date on the main form

        Technical Business Rule Format:
        WHERE PARENT RETURN EXISTS
        ^FTER174 <> ^ParentPeriodEndDate

        Data Elements:

        RP:^FTER174 = tns:Period.End.Date

        RP:^ParentPeriodEndDate = ParentPeriodEndDate
        */
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual void VRATOFTER408372()
        {
            bool assertion = !parentDocument.TRT574.Value.Equals(childDocument.FTER174.Value);
            if (assertion)
            {
                response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.FTER.408372",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Reporting period end date must match the period end date on the main form",
                    Location = "/tns:FTER/tns:RP/tns:PeriodEndD",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.FTER.408372" },
                        new ProcessMessageParameter { Name = "FTER174", Value = childDocument.FTER174.Value.ToString("yyyy-MM-dd") },
                        new ProcessMessageParameter { Name = "TRT574", Value = parentDocument.TRT574.Value.ToString("yyyy-MM-dd") }
                    }
                });
            }
        }

        #endregion // VR.ATO.FTER.408372 

        private DateTime AsDate(string dateAsString)
        {
            DateTime response = DateTime.MinValue;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
                response = date;

            return response;
        }

        #endregion
    }
}