module EasyEntityImports
  class EasyJiraXmlImporter < EasyEntityXmlImport

    def initialize
      @logger = EasyEntityImports::ImportLogger.new
    end

    def import(file=nil, entities=nil)
      User.current.as_admin do
        @results = {}

        begin
          @xml = Nokogiri::XML.parse(file.read) if file
        rescue
          @logger.log_fatal_error(I18n.t('easy_imports.file_could_not_be_processed'))
          return false
        end

        import_entities('User', @xml.xpath('//User')) if !entities || entities.include?(:users)
        import_entities('Group', @xml.xpath('//Group')) if !entities || entities.include?(:groups)
        import_entities('IssueStatus', @xml.xpath('//Status')) if !entities || entities.include?(:issue_statuses)
        import_entities('IssuePriority', @xml.xpath('//Priority')) if !entities || entities.include?(:issue_priorities)
        import_entities('Tracker', @xml.xpath('//IssueType')) if !entities || entities.include?(:trackers)
        import_entities('Project', @xml.xpath('//Project')) if !entities || entities.include?(:projects)
        import_entities('Issue', @xml.xpath('//Issue')) if !entities || entities.include?(:issues)
        # import_entities('Journal', @xml.xpath('//Action[@type = "comment"]')) if !entities || entities.include?(:journals)
        # import_customfields if !entities || entities.include?(:custom_fields)
        # import_attachments(File.join(File.dirname(file), 'data', 'attachments')) if !entities || entities.include?(:attachments)

        if @results.find{ |_,v| v.present? }
          true
        else
          @logger.log_fatal_error(I18n.t('easy_imports.no_valid_data_found'))
          false
        end
      end
    end

    def import_entities(type, collection)
      type_name = type.underscore.pluralize
      if respond_to?("import_#{type_name}", true)
        @results[type_name.to_sym] = send("import_#{type_name}", collection)
      else
        entities = {}
        klass = type.constantize
        klass.transaction do
          collection.each do |xpath|
            unless (entity = klass.find_by(name: xpath['name']))
              entity = klass.new(name: xpath['name'], position: xpath['sequence'], easy_external_id: xpath['id'])
              entity.save!(validate: false)
              @logger.log_entity_creation entity
            else
              @logger.log_entity_mapping entity
            end
            entities.store(xpath['id'], entity.id)
          end
        end

        @results[type_name.to_sym] = entities
      end
      puts "Jira importer import #{type} successfully"
    end

    # def import_attachments(folder = './data/attachments')
    #   f = File.expand_path(folder)
    #   Attachment.transaction do
    #     User.current.as_admin do
    #       @xml.xpath('//FileAttachment').each do |xpath|
    #         issue_id = get_issue_id(xpath['issue'])
    #         author_id = get_user_id(xpath['author'])
    #         file = Pathname(%x(find #{f} -name "#{xpath['id']}" -type f).strip)
    #         if file.exist? && issue_id && !Attachment.where(easy_external_id: xpath['id']).exists?
    #           begin; date = Time.parse(xpath['created']) rescue nil; end
    #             File.open(file) do |t|
    #               Attachment.create!(file: t, filename: xpath['filename'], author_id: author_id || User.current.id, container_type: 'Issue', container_id: issue_id, easy_external_id: xpath['id'], created_on: date)
    #             end
    #         end
    #       end
    #     end
    #   end
    # end

    def get_issue_id(jira_issue)
      raise ArgumentError.new('You need to process issues firstly !') if @results[:issues].nil?
      @results[:issues][jira_issue].presence
    end

    def get_user_id(jira_login)
      (@results[:users] && @results[:users][jira_login].presence) || User.like(jira_login).first.try(:id)
    end

    def log
      @logger.log
    end

    private

    # def import_customfields
    #   custom_fields = {}
    #   @xml.xpath('//CustomField').each do |xpath|
    #     unless (cf = CustomField.find_by(easy_external_id: xpath['id']))
    #       cf = case xpath['customfieldtypekey']
    #            when 'com.atlassian.jira.plugin.system.customfieldtypes:multiselect'
    #              IssueCustomField.new(field_format: 'list', multiple: true)
    #            when 'com.atlassian.jira.plugin.system.customfieldtypes:multicheckboxes'
    #              IssueCustomField.new(field_format: 'list', multiple: true, edit_tag_style: 'check_box')
    #            when 'com.atlassian.jira.plugin.system.customfieldtypes:radiobuttons'
    #              IssueCustomField.new(field_format: 'list', multiple: false, edit_tag_style: 'check_box')
    #            when 'com.atlassian.jira.plugin.system.customfieldtypes:float'
    #              IssueCustomField.new(field_format: 'float')
    #            end
    #       next if cf.nil?
    #       cf.name = xpath['name']
    #       cf.description = xpath['description']
    #       cf.easy_external_id = xpath['id']
    #       cf.is_for_all = true
    #       @logger.log_entity_creation cf
    #     else
    #       @logger.log_entity_mapping cf
    #     end
    #     custom_fields.store(cf.easy_external_id.to_s, cf)
    #   end
    #
    #   custom_field_value = {}
    #
    #   @xml.xpath('//CustomFieldOption').each do |xpath|
    #     if (cf = custom_fields[xpath['customfield']])
    #       cf.possible_values += [xpath['value']]
    #       custom_field_value.store(xpath['id'], xpath['value'])
    #     end
    #   end
    #
    #   CustomField.transaction do
    #     custom_fields.values.map(&:save!)
    #   end
    #
    #   # Import custom values
    #   CustomValue.transaction do
    #     custom_fields.each do |id, cf|
    #       @xml.xpath(%Q{//CustomFieldValue[@customfield = "#{id}"]}).each do |xpath|
    #         if (issue_id = get_issue_id(xpath['issue']))
    #           CustomValue.create(custom_field_id: cf.id, customized_type: 'Issue', customized_id: issue_id, value: custom_field_value[xpath['stringvalue']] || xpath['textvalue'] || xpath['floatvalue'])
    #         end
    #       end
    #     end
    #   end
    #
    # end

    def import_issues(xml_issues)
      attribute_assignments = [
          EasyEntityImportAttributesAssignment.new(source_attribute: 'summary', entity_attribute: 'subject'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'created', entity_attribute: 'created_on'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'updated', entity_attribute: 'updated_on'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'id', entity_attribute: 'easy_external_id')
      ]
      issues = {}
      fallback_tracker_id = Tracker.first.id
      fallback_status_id = IssueStatus.first.id
      fallback_priority_id = IssuePriority.first.id
      Issue.transaction do
        xml_issues.each do |xpath|
          unless (issue = Issue.find_by(easy_external_id: xpath['id']))
            if (project = Project.find_by(id: @results[:projects][xpath['project']]))
              issue = project.issues.build(author_id: (@results[:users] && @results[:users][xpath['creator']]) || User.current.id)
            else
              issue = Issue.new(name: xpath['summary'])
              @logger.log_entity_error(issue, nil, "#{I18n.t('easy_imports.issue_could_not_be_created', issue_name: xpath['summary'])} #{I18n.t('easy_imports.no_project_for_task')}")
              raise ArgumentError.new('No project for task ')
            end
            issue.assigned_to_id = get_user_id(xpath['assignee'])
            issue.priority_id = @results[:issue_priorities][xpath['priority']].presence || fallback_priority_id
            issue.tracker_id = @results[:trackers][xpath['type']].presence || project.tracker_ids.first || fallback_tracker_id
            project.trackers << issue.tracker unless project.tracker_ids.include?(issue.tracker_id)
            issue.status_id = @results[:issue_statuses][xpath['status']].presence || fallback_status_id
            assign_attribute_for(issue, attribute_assignments, xpath)
            issue.save!(validate: false)
            @logger.log_entity_creation issue
          else
            @logger.log_entity_mapping issue
          end
          issues.store(issue.easy_external_id, issue.id)
        end
      end

      issues
    end

    # def import_journals(xml_journals)
    #   Journal.transaction do
    #     xml_journals.each do |xpath|
    #       issue_id = get_issue_id(xpath['issue'])
    #       next if issue_id.nil?
    #       key = "easy_external_id_#{xpath['id']}"
    #       author_id = get_user_id(xpath['updateauthor'])
    #       next if Journal.where(journalized_type: 'Issue', easy_type: key).exists?
    #       begin; date = Time.parse(xpath['created']) rescue nil; end
    #       Journal.create(journalized_id: issue_id, journalized_type: 'Issue', user_id: author_id || User.current.id, notes: xpath['body'], created_on: date, easy_type: key)
    #     end
    #   end
    # end

    def import_projects(xml_projects)
      attribute_assignments = [
          EasyEntityImportAttributesAssignment.new(source_attribute: 'name', entity_attribute: 'name'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'description', entity_attribute: 'description'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'key', entity_attribute: 'identifier'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'id', entity_attribute: 'easy_external_id')
      ]
      projects = {}
      Project.transaction do
        xml_projects.each do |xpath|
          unless (project = Project.find_by(easy_external_id: xpath['id']))
            project = Project.new(author_id: User.current.id)
            project.enable_module!('easy_wbs')
            assign_attribute_for(project, attribute_assignments, xpath)
            project.tracker_ids = @results[:trackers].values.flatten

            begin
              warnings = (project.errors.full_messages) unless project.valid?
              raise unless EasyLicenseManager.has_license_limit?(:active_project_limit)
              project.save!(validate: false)
              project.init_overview_page
              @logger.log_entity_creation project
              @logger.log_entity_warning(project, nil, warnings) if warnings.present?
            rescue
              @logger.log_entity_error(project, project.name, "#{I18n.t('easy_imports.project_could_not_be_created', project_name: project.name)}<ul>#{project.errors.full_messages.map { |m| "<li>#{m}</li>" }.join}</ul>".html_safe)
              project = nil
            end
          else
            @logger.log_entity_mapping project
          end
          projects.store(project.easy_external_id, project.id) unless project.new_record?
        end
      end

      projects
    end

    def import_users(xml_users)
      attribute_assignments = [
          EasyEntityImportAttributesAssignment.new(source_attribute: 'userName', entity_attribute: 'login'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'firstName', entity_attribute: 'firstname'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'lastName', entity_attribute: 'lastname'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'emailAddress', entity_attribute: 'mail'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'id', entity_attribute: 'easy_external_id')
      ]
      users = {}
      t = User.arel_table
      User.transaction do
        xml_users.each do |xpath|
          if (user = User.where(t[:easy_external_id].eq(xpath['id']).or(t[:easy_external_id].eq(nil).and(t[:login].eq(xpath['userName'])))).first)
            user.update_column(:easy_external_id, xpath['id']) if user.easy_external_id.blank?
            @logger.log_entity_mapping user
          else
            # User already exists
            user = User.new
            assign_attribute_for(user, attribute_assignments, xpath)
            user.status = User::STATUS_LOCKED unless xpath['active'] != '1'
            user.password = "#{user.login}686"
            user.save!(validate: false)
            @logger.log_entity_creation user
          end
          users.store(user.login, user.id)
        end
      end

      users
    end

    def import_groups(xml_groups)
      attribute_assignments = [
          EasyEntityImportAttributesAssignment.new(source_attribute: 'groupName', entity_attribute: 'lastname'),
          EasyEntityImportAttributesAssignment.new(source_attribute: 'id', entity_attribute: 'easy_external_id')
      ]
      groups = {}
      t = Group.arel_table
      User.transaction do
        xml_groups.each do |xpath|
          if (group = Group.where(t[:easy_external_id].eq(xpath['id']).or(t[:easy_external_id].eq(nil).and(t[:lastname].eq(xpath['groupName'])))).first)
            group.update_column(:easy_external_id, xpath['id']) if group.easy_external_id.blank?
            @logger.log_entity_mapping group
          else
            # Group already exists
            group = Group.new
            assign_attribute_for(group, attribute_assignments, xpath)
            group.save!(validate: false)
            @logger.log_entity_creation group
          end
          groups.store(group.login, group.id)
        end
      end

      groups
    end

    def assign_attribute_for(entity, assignments, xpath)
      assignments.each do |attrs|
        entity.send("#{attrs.entity_attribute}=", xpath[attrs.source_attribute])
      end
    end

  end
end
