module ReportsService
    class EmployerCardComparisons

        def initialize(pl_plan_keys)
            @pl_plan_keys = Array.wrap(pl_plan_keys)
            @hlid_ids_compared = []
        end

        def call
            @pl_plan_keys.each do |pl_plan_key|
                employer = Employer.find_by(pl_plan_key: pl_plan_key)
                employer_card_comparison = Report::EmployerCardComparison.find_or_create_by(pl_plan_key: pl_plan_key)
                employer_card_comparison.employer_name = employer.name

                AutomationService::EmployerMembersUpdate.new(pl_plan_key).call
                employer_member_keys = employer.employer_member_keys
                IdCard::PrintData.where(pl_plan_key:  pl_plan_key).destroy_all
                IdCardPrinterService::CardDataFormatter.new(employer_member_keys).call
                IdCard::PrintData.where(pl_plan_key: pl_plan_key, primary_mb_member_key: nil).destroy_all

                new_card_member_keys = IdCard::PrintData.where(pl_plan_key: pl_plan_key).pluck(:primary_mb_member_key).uniq
                old_card_member_keys = Report::OldCardDuplicate.where(pl_plan_key: pl_plan_key).pluck(:primary_mb_member_key).uniq.map(&:to_s)

                missing_from_new = old_card_member_keys - new_card_member_keys
                missing_from_old = new_card_member_keys - old_card_member_keys

                if missing_from_new.present? || missing_from_old.present?
                    comp_error = employer_card_comparison.comparison_errors.find_or_create_by(card_field: "Missing Cards")
                    comp_error.update(new_value: missing_from_old.join(', '), old_value: missing_from_new.join(', '))
                end

                employer_card_comparison.new_cards_count = new_card_member_keys.count
                employer_card_comparison.old_cards_count = old_card_member_keys.count

                member_keys_array = new_card_member_keys | old_card_member_keys
                member_keys_array.each do |member_key|
                    compare_member_cards(member_key, pl_plan_key, employer_card_comparison.id)
                end

                employer_card_comparison.total_errors_count = employer_card_comparison.employer_total_errors
                if employer_card_comparison.total_errors_count == 0
                    employer_card_comparison.passed = true
                end

                employer_card_comparison.save

            end
        end

        private

        def compare_member_cards(member_pb_entity_key, pl_plan_key, employer_card_comparison_id)
            member_card_comparison = Report::MemberCardComparison.find_or_create_by(member_number: member_pb_entity_key, pl_plan_key: pl_plan_key, employer_card_comparison_id: employer_card_comparison_id)
            new_card = IdCard::PrintData.find_by(primary_mb_member_key:  member_pb_entity_key)
            old_card = Report::OldCardDuplicate.find_by(primary_mb_member_key: member_pb_entity_key)

            current_errors = []
            if new_card.present? && old_card.present?
                new_card_common = new_card.attributes.with_indifferent_access.except(
                    :id, :created_at, :full_name_last_name_first, :network_provider, :plan_id, 
                    :network_logo_filename, :employer_logo_filename, :sample_plan_title, :jasper_batch_id, :updated_at,
                    :dependent_1, :dependent_2, :dependent_3, :dependent_4, :dependent_5, :dependent_6, :dependent_7, :dependent_8,
                    :precert_1, :precert_2, :precert_3, :precert_4
                )
                new_card_common.delete_if { |key, value| key.match?(/[[:upper:]]/) }

                new_card_dependents = new_card.attributes.with_indifferent_access.slice(
                    :dependent_1, :dependent_2, :dependent_3, :dependent_4, :dependent_5, :dependent_6, :dependent_7, :dependent_8
                )
                new_card_dependents.delete_if { |key, value| key.match?(/[[:upper:]]/) }

                new_card_dental = new_card[:dental_coverage]
                new_card_eff_date = new_card[:medical_eff_date]

                old_card_common = old_card.attributes.with_indifferent_access.except(
                    :id, :created_at, :updated_at, :dental_coverage, :medical_eff_date,
                    :dependent_1, :dependent_2, :dependent_3, :dependent_4, :dependent_5, :dependent_6, :dependent_7, :dependent_8,
                    :precert_1, :precert_2, :precert_3, :precert_4
                )
                if pl_plan_key = '2'
                    old_card_common.except!(
                        :benefit_desc_1, :benefit_1, :benefit_desc_2, :benefit_2, :benefit_desc_3, :benefit_3, 
                        :benefit_desc_4, :benefit_4, :benefit_desc_5, :benefit_5, :benefit_desc_6, :benefit_6, :benefit_desc_7, :benefit_7, :benefit_desc_8, :benefit_8, 
                        :benefit_desc_9, :benefit_9, :benefit_desc_10, :benefit_10, :benefit_desc_11, :benefit_11, :benefit_desc_12, :benefit_12, :benefit_desc_13, :benefit_13, 
                        :benefit_desc_14, :benefit_14
                    )
                end
                old_card_common.delete_if { |key, value| key.match?(/[[:upper:]]/) }

                old_card_dependents = old_card.attributes.with_indifferent_access.slice(
                    :dependent_1, :dependent_2, :dependent_3, :dependent_4, :dependent_5, :dependent_6, :dependent_7, :dependent_8
                )
                old_card_dependents.delete_if { |key, value| key.match?(/[[:upper:]]/) }

                old_card_dental = old_card[:dental_coverage]
                old_card_eff_date = old_card[:medical_eff_date]

                old_card_common.each do |key, value|
                    unless new_card_common[key].to_s.downcase.squish.gsub(/\W/, ' ') == value.to_s.downcase.squish.gsub(/\W/, ' ')
                        comp_error = member_card_comparison.comparison_errors.find_or_create_by(card_field: key.to_s)
                        comp_error.assign_attributes(new_value: new_card_common[key], old_value: value)
                        current_errors << comp_error
                    end
                end

                unless old_card_dependents.values.map(&:squish).sort == new_card_dependents.values.map(&:squish).sort
                    missing_from_new = (old_card_dependents.values - new_card_dependents.values).compact_blank
                    missing_from_old = (new_card_dependents.values - old_card_dependents.values).compact_blank

                    comp_error = member_card_comparison.comparison_errors.find_or_create_by(card_field: "Missing Dependent(s)")
                    comp_error.assign_attributes(new_value: missing_from_old.join(', '), old_value: missing_from_new.join(', '))
                    current_errors << comp_error
                end

                unless (new_card_dental == old_card_dental) || (old_card_dental == "NONE" && new_card_dental.empty?)
                    comp_error = member_card_comparison.comparison_errors.find_or_create_by(card_field: "dental_coverage")
                    comp_error.assign_attributes(new_value: new_card_dental, old_value: old_card_dental)
                    current_errors << comp_error
                end

                unless (old_card_eff_date.present?) || (convert_to_date(new_card_eff_date) == convert_to_date(old_card_eff_date))
                    comp_error = member_card_comparison.comparison_errors.find_or_create_by(card_field: "medical_eff_date")
                    comp_error.assign_attributes(new_value: new_card_eff_date, old_value: old_card_eff_date)
                    current_errors << comp_error
                end
            else
                comp_error = member_card_comparison.comparison_errors.find_or_create_by(card_field: "Missing Member")

                comp_error.assign_attributes(
                    new_value: new_card.presence&.primary_mb_member_key || "Missing", 
                    old_value: old_card.presence&.primary_mb_member_key || "Missing"
                )
                current_errors << comp_error
            end
            member_card_comparison.comparison_errors = current_errors
            if current_errors.empty?
                member_card_comparison.passed = true
            end
            member_card_comparison.save
        end

        def convert_to_date(string_date)
            string_date.presence&.then { |s| Date.strptime(s, '%m/%d/%Y') }
        end

    end
end