require File.expand_path('../../spec_helper', __FILE__)

describe Issue do

  describe 'available_custom_fields', logged: true do
    let!(:issue_cf_forall) { FactoryGirl.create(:issue_custom_field, is_for_all: true) }
    let(:issue_cf) { FactoryGirl.create(:issue_custom_field, is_for_all: false) }
    let!(:tracker1) { FactoryGirl.create(:tracker) }
    let!(:tracker2) { FactoryGirl.create(:bug_tracker, issue_custom_fields: [issue_cf_forall, issue_cf]) }
    let(:project1) { FactoryGirl.create(:project, number_of_issues: 0, add_modules: ['issue_tracking']) }
    let(:project2) { FactoryGirl.create(:project, number_of_issues: 0, issue_custom_fields: [issue_cf], add_modules: ['issue_tracking']) }
    let(:issue1) { FactoryGirl.create(:issue, author: User.current, project: project1, tracker: tracker1)  }
    let(:issue2) { FactoryGirl.create(:issue, author: User.current, project: project1, tracker: tracker2)  }
    let(:issue3) { FactoryGirl.create(:issue, author: User.current, project: project2, tracker: tracker1)  }
    let(:issue4) { FactoryGirl.create(:issue, author: User.current, project: project2, tracker: tracker2)  }

    it 'gives right correctly sorted answers without cache' do
      expect(issue1.available_custom_fields.collect(&:id)).to eq([])
      expect(issue2.available_custom_fields.collect(&:id)).to eq([issue_cf_forall.id])
      expect(issue3.available_custom_fields.collect(&:id)).to eq([])
      expect(issue4.available_custom_fields.collect(&:id)).to eq([issue_cf_forall.id, issue_cf.id])
    end

    it 'gives right correctly sorted answers with cache' do
      Issue.load_available_custom_fields_cache([project1.id, project2.id])
      expect{ Issue.load_available_custom_fields_cache([project1.id]) }.to_not raise_error #it does not fail to call cache twice with same ids
      expect(issue1.available_custom_fields.collect(&:id)).to eq([])
      expect(issue2.available_custom_fields.collect(&:id)).to eq([issue_cf_forall.id])
      expect(issue3.available_custom_fields.collect(&:id)).to eq([])
      expect(issue4.available_custom_fields.collect(&:id)).to eq([issue_cf_forall.id, issue_cf.id])
    end

    it 'loads all projects without project_ids' do
      project1; project2
      Issue.load_available_custom_fields_cache
      expect(Issue.available_custom_fields_from_cache(project1.id, tracker1.id).collect(&:id)).to eq([])
      expect(Issue.available_custom_fields_from_cache(project1.id, tracker2.id).collect(&:id)).to eq([issue_cf_forall.id])
      expect(Issue.available_custom_fields_from_cache(project2.id, tracker1.id).collect(&:id)).to eq([])
      expect(Issue.available_custom_fields_from_cache(project2.id, tracker2.id).collect(&:id)).to eq([issue_cf_forall.id, issue_cf.id])
    end

  end

  describe 'status change', :logged => :admin do
    let(:project) { FactoryGirl.create(:project, enabled_module_names: ['issue_tracking'], number_of_issues: 0) }
    let(:cf_datetime) { FactoryGirl.create(:issue_custom_field, field_format: 'datetime', is_for_all: true, is_filter: true, trackers: project.trackers, max_length: 25) }
    let(:issue) do
      _issue = FactoryGirl.create(:issue, project: project, due_date: Date.today)
      _issue.reload
      _issue.custom_field_values = {
          cf_datetime.id.to_s => {date: Date.today, hour: 10, minute: 10},
      }
      _issue.save!
      _issue
    end
    let(:issue_status2) { FactoryGirl.create(:issue_status) }

    it 'datetime cf wont be changed' do
      original_value = issue.custom_field_value(cf_datetime)
      with_easy_settings(:skip_workflow_for_admin => true) do
        issue.safe_attributes = {'status_id' => issue_status2.id.to_s}
        issue.save
      end
      reloaded = Issue.find_by(:id => issue.id)
      expect(reloaded.status_id).to eq(issue_status2.id)
      expect(issue.custom_field_value(cf_datetime)).to eq(original_value)
    end
  end

  describe 'advanced functionality', logged: :admin do
    let!(:issue1) { FactoryGirl.create(:issue, :with_journals).reload }
    let!(:issue2) { FactoryGirl.create(:issue, :with_journals).reload }
    let!(:issue3) { FactoryGirl.create(:issue, :with_journals).reload }
    let!(:closed_status) { FactoryGirl.create(:issue_status, :closed) }
    let!(:issue_with_description1) { FactoryGirl.create(:issue, :with_description) }
    let!(:issue_with_description2) { FactoryGirl.create(:issue, :with_description) }
    let!(:issue_without_description) { FactoryGirl.create(:issue) }

    let(:project_with_subprojects) { FactoryGirl.create(:project, :with_subprojects) }
    let(:project2) { FactoryGirl.create(:project, enabled_module_names: ['issue_tracking']) }

    it 'merges issues correctly into issue1' do
      issue1_journals_count = issue1.journals.size
      journals_count = Journal.count
      issue2_journals_count = issue2.journals.size
      issue3_journals_count = issue3.journals.size

      Issue.easy_merge_and_close_issues([issue2, issue3], issue1)

      # increment by 1, add info journal to first issue
      expect(issue1.journals.size).to eq(1 + issue1_journals_count + issue2_journals_count + issue3_journals_count)

      # increment by 3, every merging add one info journal
      expect(Journal.count).to eq(3 + issue1_journals_count + issue2_journals_count*2 + issue3_journals_count*2)
    end

    it 'merges descriptions correctly' do
      Issue.easy_merge_and_close_issues([issue_with_description1, issue_with_description2], issue_with_description1)

      expect(issue_with_description1.description.to_s).to include(issue_with_description1.description.to_s)
      expect(issue_with_description1.description.to_s).to include(issue_with_description2.description.to_s)

      Issue.easy_merge_and_close_issues([issue_without_description, issue_with_description1], issue_without_description)

      expect(issue_without_description.description.to_s).to include(issue_without_description.description.to_s)
      expect(issue_without_description.description.to_s).to include(issue_with_description1.description.to_s)
    end

    it 'moves issue between projects' do
      issue1.project = project2
      issue1.save
      expect(issue1.project).to eq project2
    end

    it 'creates correct issue relations from template with subprojects' do
      project_with_subprojects
      project_with_subprojects.reload
      issue_relation = IssueRelation.new

      first_subproject = project_with_subprojects.descendants.first
      last_subproject = project_with_subprojects.descendants.last

      issue_relation.issue_from = first_subproject.issues.first
      issue_relation.issue_to = last_subproject.issues.first

      with_settings(:cross_project_issue_relations => '1') do
        issue_relation.save

        templates = project_with_subprojects.create_project_templates(:copying_action => :creating_template, :copy_author => true)

        expect(templates[:unsaved].count).to eq 0
        template_subproject = templates[:saved].last.reload

        expect(IssueRelation.includes(:issue_from => :project).where(:projects => {:id => template_subproject.id}).count + IssueRelation.includes(:issue_to => :project).where(:projects => {:id => template_subproject.id}).count).to eq 1

        template_root = template_subproject.root.reload

        project_attributes = template_root.self_and_descendants.where("#{Project.table_name}.status <> ?", Project::STATUS_ARCHIVED).select([:id,:name]).collect { |p| {'id' => p.id.to_s, 'name' => p.name} }

        new_project, saved_projects, unsaved_projects = template_root.project_with_subprojects_from_template('', project_attributes, {:copying_action => :creating_project, :copy_author => true, :easy_start_date => Date.today})

        expect(unsaved_projects.to_a.count).to eq 0
        template_subproject = saved_projects.last

        expect(IssueRelation.includes(:issue_from => :project).where(:projects => {:id => template_subproject.id}).count + IssueRelation.includes(:issue_to => :project).where(:projects => {:id => template_subproject.id}).count).to eq 1
      end
    end

    context 'replace %task_last_journal% comment with last non private journals' do
      def replace_last_journal_comment
        last_journal_comment = issue1.journals.visible.where(:private_notes => false).with_notes.order(:created_on => :desc).first
        last_journal_comment_notes = issue1.format_journal_for_mail_template(last_journal_comment)

        expect(issue1.replace_last_non_private_comment('%task_last_journal%')).to eq last_journal_comment_notes
        if Redmine::Plugin.installed?(:easy_helpdesk)
          expect(issue1.easy_helpdesk_replace_tokens('%task_last_journal%')).to eq last_journal_comment_notes
        end

        expect(issue1.replace_last_non_private_comment('%task_last_journal%', last_journal_comment)).not_to eq last_journal_comment_notes
        if Redmine::Plugin.installed?(:easy_helpdesk)
          expect(issue1.easy_helpdesk_replace_tokens('%task_last_journal%', last_journal_comment)).not_to eq last_journal_comment_notes
        end
      end

      it 'replaces the last journal' do
        replace_last_journal_comment
      end

      it 'replaces the last non private journal' do
        last_journal_comment = issue1.journals.visible.where(:private_notes => false).with_notes.order(:created_on => :desc).first
        last_journal_comment.update_attribute(:private_notes, true)
        replace_last_journal_comment
      end
    end
  end

end
