# frozen_string_literal: true

require_dependency "renalware/ukrdc"
require "attr_extras"

module Renalware
  module UKRDC
    module Incoming
      # Encapsulates the structure of the UKRDC XML Document.
      # Assumes one patient per file.
      class XmlDocument
        XPATHS = {
          dob: "string(Patient[1]/BirthTime)",
          family_name: "string(Patient[1]/Names[1]/Name/Family)",
          nhs_number: <<-XPATH.squish
            string(
              Patient[1]/
                PatientNumbers/
                  PatientNumber[Organization[text()='NHS']][NumberType[text()='MRN']][1]/
                    Number
            )
          XPATH
        }.freeze

        attr_reader :root

        def initialize(file)
          xml_document = File.open(file) { |f| Nokogiri::XML(f) }
          @root = xml_document.root
        end

        # Accessing eg XmlDocument.new(file).nhs_number will search the document with looked-up
        # entry in the XPATHS constant, to save us having to write attributes for the things we
        # need.
        def method_missing(method_name, *_args, &_block)
          xpath = XPATHS[method_name]
          return root.xpath(xpath) if xpath

          super
        end

        def respond_to_missing?(method_name, *_args)
          XPATHS.key?(method_name)
        end

        # Turn the surveys XML into a hash becuase it is easier to consume
        def surveys
          root.xpath("Surveys/Survey").each_with_object([]) do |survey_node, arr|
            hash = {}
            hash[:code] = survey_node.xpath("string(SurveyType/Code)")
            hash[:time] = survey_node.xpath("string(SurveyTime)")
            hash[:responses] = question_hash_from(survey_node)
            arr << hash
          end
        end

        # Note that if a response has a QuestionText this can be some text the user entered
        # (presumably so they can then assign it a response value) so we need to store the
        # question text (e.g. Paranoia) as well as the response (eg 4).
        # If we find a QuestionText we store an array containing it and the response in the hash
        # otherwise we just add the response.
        def question_hash_from(survey_node)
          question_nodes = survey_node.xpath("Questions/Question")
          question_nodes.each_with_object({}) do |question_node, responses|
            code = question_node.xpath("string(QuestionType/Code)")
            response = question_node.xpath("string(Response)")
            question_text = question_node.xpath("string(QuestionText)")
            responses[code] = if question_text.present?
                                [response, question_text]
                              else
                                response
                              end
          end
        end
      end
    end
  end
end