require 'fileutils'
module HealthDataStandards
  module Import
    class BulkRecordImporter

      def self.import_directory(source_dir, failed_dir=nil)
        failed_dir ||= File.join(source_dir, '../', 'failed_imports')
        files = Dir.glob(File.join(source_dir, '*.*'))
        files.each do |file|
	   self.import_file(file,File.new(file).read,failed_dir)
        end
      end

      def self.import_archive(file, failed_dir=nil)
        begin
        failed_dir ||=File.join(File.dirname(file))

        patient_id_list = nil

        Zip::ZipFile.open(file.path) do |zipfile|
          zipfile.entries.each do |entry|
            if entry.name
              if entry.name.split("/").last == "patient_manifest.txt"
                patient_id_list = zipfile.read(entry.name)
                next
              end
            end
            next if entry.directory?
            data = zipfile.read(entry.name)
	    self.import_file(entry.name,data,failed_dir)
          end
        end

        missing_patients = []

        #if there was a patient manifest, theres a patient id list we need to load
        if patient_id_list
          patient_id_list.split("\n").each do |id|
            patient = Record.where(:medical_record_number => id).first
            if patient == nil
              missing_patients << id
            end
          end
        end

        missing_patients

      rescue
        FileUtils.mkdir_p(failed_dir)
        FileUtils.cp(file,File.join(failed_dir,File.basename(file)))
        File.open(File.join(failed_dir,"#{file}.error")) do |f|
          f.puts($!.message)
          f.puts($!.backtrace)
        end
        raise $!
      end
      end

      def self.import_file(name,data,failed_dir,provider_map={})
        begin
          ext = File.extname(name)
          if ext == ".json"
	    self.import_json(data)
          else
	    self.import(data)
          end
        rescue
          FileUtils.mkdir_p(File.dirname(File.join(failed_dir,name)))
          File.open(File.join(failed_dir,name),"w") do |f|
            f.puts(data)
          end
          File.open(File.join(failed_dir,"#{name}.error"),"w") do |f|
            f.puts($!.message)
            f.puts($!.backtrace)
          end
        end
      end

      def self.import_json(data,provider_map = {})
        json = JSON.parse(data,:max_nesting=>100)
        record = Record.update_or_create(Record.new(json))
        providers = record.provider_performances
        providers.each do |prov|
          prov.provider.ancestors.each do |ancestor|
            record.provider_performances.push(ProviderPerformance.new(start_date: prov.start_date, end_date: prov.end_date, provider: ancestor))
          end
        end
        record.save!
      end

      def self.import(xml_data, provider_map = {})
        doc = Nokogiri::XML(xml_data)

        providers = []
        root_element_name = doc.root.name

        if root_element_name == 'ClinicalDocument'
          doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
          doc.root.add_namespace_definition('sdtc', 'urn:hl7-org:sdtc')

          if doc.at_xpath("/cda:ClinicalDocument/cda:templateId[@root='2.16.840.1.113883.3.88.11.32.1']")
            patient_data = C32::PatientImporter.instance.parse_c32(doc)
          elsif doc.at_xpath("/cda:ClinicalDocument/cda:templateId[@root='2.16.840.1.113883.10.20.22.1.2']")
            patient_data = CCDA::PatientImporter.instance.parse_ccda(doc)
          elsif doc.at_xpath("/cda:ClinicalDocument/cda:templateId[@root='2.16.840.1.113883.10.20.24.1.2']")
            patient_data = Cat1::PatientImporter.instance.parse_cat1(doc)
          else
            STDERR.puts("Unable to determinate document template/type of CDA document")
            return {status: 'error', message: "Document templateId does not identify it as a C32 or CCDA", status_code: 400}
          end

          record = Record.update_or_create(patient_data)

          begin
            providers = CDA::ProviderImporter.instance.extract_providers(doc, record)
          rescue Exception => e
            STDERR.puts "error extracting providers"
          end
        else
          return {status: 'error', message: 'Unknown XML Format', status_code: 400}
        end

        record.provider_performances = providers
        providers.each do |prov|
          prov.provider.ancestors.each do |ancestor|
            record.provider_performances.push(ProviderPerformance.new(start_date: prov.start_date, end_date: prov.end_date, provider: ancestor))
          end
        end
        record.save

        record
      end
    end
  end
end
