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

describe IssuesController, :logged => :admin do

  let(:project) {FactoryGirl.create(:project)}
  let(:version) {FactoryGirl.create(:version)}
  let(:issue) {FactoryGirl.create(:issue, project: project)}
  let(:issues) {FactoryGirl.create_list(:issue, 3, project: project)}
  let(:time_entry_activity) {FactoryGirl.create(:time_entry_activity, projects: [project])}
  let(:issue_with_description) {FactoryGirl.create(:issue, project: project,
     description: '<p><h1>TEST</h1></p><p><a href=https://test.com>test</a></p>')}

  describe 'GET show' do
    render_views

    it 'html' do
      get :show, :id => issue_with_description
      expect( response ).to be_success
    end

    context 'EXPORTS' do
      it 'pdf detail' do
        get :show, :format => 'pdf', :id => issue_with_description
        expect( response ).to be_success
        expect( response.content_type ).to eq( 'application/pdf' )
      end

      it 'pdf detail with html description' do
        with_settings({'text_formatting' => 'HTML'}) do
          get :show, :format => 'pdf', :id => issue_with_description
        end
        expect( response ).to be_success
        expect( response.content_type ).to eq( 'application/pdf' )
      end
    end
  end

  describe 'GET index' do
    context 'EXPORTS' do
      render_views

      before(:each) { issues }

      it 'exports index to pdf with description' do
        issue_with_description
        with_settings({'text_formatting' => 'HTML'}) do
          get :index, :format => 'pdf', set_filter: '0', easy_query: {columns_to_export: 'all'}
        end
        expect( response ).to be_success
        expect( response.content_type ).to eq( 'application/pdf' )
      end

      it 'exports index to pdf' do
        get :index, :format => 'pdf', set_filter: '0', easy_query: {columns_to_export: 'all'}
        expect( response ).to be_success
        expect( assigns(:issues) ).not_to be_nil
        expect( response.content_type ).to eq( 'application/pdf' )
      end

      it 'exports project index to pdf' do
        get :index, :project_id => project.id, :format => 'pdf', set_filter: '0', easy_query: {columns_to_export: 'all'}
        expect( response ).to be_success
        expect( assigns(:issues) ).not_to be_nil
        expect( response.content_type ).to eq( 'application/pdf' )
      end

      it 'exports to xlsx' do
        get :index, :format => 'xlsx', set_filter: '0', easy_query: {columns_to_export: 'all'}
        expect( response ).to be_success
        expect( response.content_type ).to eq( 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' )
      end

      it 'exports to csv' do
        get :index, :format => 'csv', set_filter: '0', easy_query: {columns_to_export: 'all'}
        expect( response ).to be_success
        expect( response.content_type ).to include( 'text/csv' )
      end

      it 'renders atom format' do
        get :index, :format => 'atom'
        expect( response ).to be_success
        expect( response.content_type ).to eq( 'application/atom+xml' )
        expect( assigns(:items) ).not_to be_nil
        expect( assigns(:items).first ).to be_a(Issue)
      end

      it 'renders ics format' do
        issues;
        get :index, :format => 'ics'
        expect( response ).to be_success
        expect( response.content_type ).to include( 'text/calendar' )
        expect( response.body ).not_to be_blank
      end
    end

    context 'API' do
      render_views
      let(:settings) { HashWithIndifferentAccess.new(:entity_type => 'User', :entity_attribute => 'link_with_name') }
      let(:easy_lookup_custom_field) { FactoryGirl.create(:issue_custom_field, :field_format => 'easy_lookup', :settings => settings, :multiple => true, :trackers => [issue.tracker]) }

      it 'renders issues to JSON' do
        issue_count = project.issues.count
        get :index, format: 'json', include: ['total_count']
        expect( response ).to be_success
        expect(json).to have_key(:issues)
        expect( json[:total_count] ).to eq( issue_count )
        expect( json[:issues].count ).to eq( issue_count )
      end

      it 'renders issues to JSON with lookup' do
        easy_lookup_custom_field; issue.reload
        issue.safe_attributes = {'custom_field_values' => {easy_lookup_custom_field.id.to_s => [User.current.id.to_s]}}
        issue.save; issue.reload
        get :index, :format => 'json'
        expect( response ).to be_success
        expect( response.body ).to include(User.current.name)
      end
    end

    it 'creates repeating task with right date shift' do
      allow(Date).to receive(:today).and_return(Date.new(2015, 2, 4))
      issue_attrs = FactoryGirl.attributes_for(:issue, :recurring_monthly, :project => project).merge!({project_id: project.id, easy_next_start: Date.today.next_month.beginning_of_month, start_date: Date.today.beginning_of_month, due_date: nil})
      issue_attrs[:easy_repeat_settings].merge!({simple_period: 'custom', endtype_count_x: 3, period: 'monthly', monthly_period: 1, monthly_option: 'xth', monthly_day: '1', endtype: 'count', create_now: 'all'})
      post :create, {:issue => issue_attrs }

      # expect( response ).to have_http_status(302)
      expect( response ).to redirect_to(issue_path(assigns[:issue]))

      recurring = Issue.easy_repeating.first
      recurred = recurring.relations_from.collect{|rel| rel.issue_to}

      expect( recurred.count ).to eq( 3 )

      expect( recurred.select{|recc| recc.start_date == Date.today.next_month.beginning_of_month }.count ).to eq( 1 )

    end

    it 'get new issues without available trackers' do
      project.trackers = []
      get :new, :project_id => project.id
      expect( response ).to have_http_status(500)
      expect( response ).to render_template 'common/error'
    end

  end

  it 'updates issue with spent time' do
    expect{
      put :update, :id => issue, :time_entry => {:hours => 5, :activity_id => time_entry_activity}, :issue => {:description => 'testing'}
    }.to change(TimeEntry, :count).by(1)
    issue.reload
    expect(issue.description).to eq('testing')
    expect(issue.time_entries).not_to be_blank
  end

  it 'create invalid issue (fixed version without project)' do
    expect{
      post :create, :issue => {:fixed_version_id => version.id}
    }.not_to raise_exception
  end

  it 'create issue + extend flash message' do
    project

    expect{
      post :create, :issue => {:project_id => project.id, :subject => 'test'}
    }.to change(Issue, :count).by(1)

    with_settings(:bcc_recipients => false) do
      expect{
        post :create, :issue => {:project_id => project.id, :subject => 'test'}
      }.to change(Issue, :count).by(1)
    end
  end

  context 'period days filter', :admin => true do
    render_views

    before(:each) { issues.each_with_index{|issue, i| issue.update_column(:due_date, Date.today - i.days) } }

    it '1 day' do
      get :index, :format => 'json', :set_filter => '1', :due_date => 'from_m_to_n_days|1|1'
      expect(response).to be_success
      expect(assigns(:entities).count).to eq(2)
    end

    it '5 days' do
      get :index, :format => 'json', :set_filter => '1', :due_date => 'from_m_to_n_days|5|1'
      expect(response).to be_success
      expect(assigns(:entities).count).to eq(issues.count)
    end
  end

  context 'bulk update', :logged => :admin do
    render_views

    let(:issue) { FactoryGirl.create(:issue, :description => 'issue1') }
    let(:issue2) { FactoryGirl.create(:issue, :description => 'issue2') }
    let(:test_user) { FactoryGirl.create(:user) }

    it 'author' do
      put :bulk_update, :ids => [issue.id, issue2.id], :issue => {:author_id => test_user.id}
      i1 = Issue.find(issue.id); i2 = Issue.find(issue2.id)
      expect(i1.author_id).to eq(test_user.id)
      expect(i2.author_id).to eq(test_user.id)
    end

    it 'invalid author' do
      put :bulk_update, :ids => [issue.id, issue2.id], :issue => {:author_id => nil}
      i1 = Issue.find(issue.id); i2 = Issue.find(issue2.id)
      expect(i1.author_id).not_to eq(nil)
      expect(i2.author_id).not_to eq(nil)
    end

    context 'merge' do
      let(:issue_status) { FactoryGirl.create(:issue_status, :is_closed => true) }

      before(:each) do
        issue; issue2; issue_status
      end

      after(:each) do
        i1 = Issue.find(issue.id); i2 = Issue.find(issue2.id)
        expect(i1.closed?).to eq(true)
        expect(i2.closed?).to eq(false)
        expect(i2.description).to include('issue1')
        expect(i2.description).to include('issue2')
        expect([404, 500].include?(response.status)).to eq(false)
      end

      it 'html' do
        put :bulk_update, :ids => [issue.id], :issue => {:merge_to_id => issue2.id}, :merge => '1'
      end

      it 'json' do
        put :bulk_update, :ids => [issue.id], :issue => {:merge_to_id => issue2.id}, :merge => '1', :format => 'json'
      end
    end
  end

  context 'permissions', :logged => true do
    let!(:project) {FactoryGirl.create(:project, :enabled_module_names => ['issue_tracking'], :members => [User.current])}
    let(:issue) {FactoryGirl.create(:issue, :project => project, :author => User.current)}

    it 'with edit_own_issue' do
      role = User.current.roles.first
      role.remove_permission!(:edit_issues)
      role.add_permission!(:edit_own_issue)
      role.reload
      put :update, :id => issue, :issue => {:description => 'testing'}
      issue.reload
      expect(issue.description).to eq('testing')
    end

    it 'with edit_assigned_issue' do
      role = User.current.roles.first
      role.remove_permission!(:edit_issues)
      role.add_permission!(:edit_assigned_issue)
      role.reload
      put :update, :id => issue, :issue => {:description => 'testing'}
      issue.reload
      expect(issue.description).to eq('testing')
    end

    it 'with edit_issues' do
      role = User.current.roles.first
      role.add_permission!(:edit_issues)
      role.remove_permission!(:edit_own_issue)
      role.reload
      put :update, :id => issue, :issue => {:description => 'testing'}
      issue.reload
      expect(issue.description).to eq('testing')
    end

    it 'without edit_issues' do
      role = User.current.roles.first
      role.remove_permission!(:edit_issues, :edit_own_issue, :add_issue_notes)
      role.reload
      put :update, :id => issue, :issue => {:description => 'testing'}
      issue.reload
      expect(issue.description).not_to eq('testing')
    end
  end

  context 'journals' do

    let(:issue_category) {FactoryGirl.create(:issue_category, :project => project)}
    let!(:issue_parent1) { FactoryGirl.create(:issue, :project => project, :due_date => nil) }
    let!(:issue_parent2) { FactoryGirl.create(:issue, :project => project, :due_date => nil) }

    render_views

    it 'should not create journal detail when a date column is changed' do
      expect{ put :update, :id => issue, :issue => {:due_date => User.current.today + 1.day} }.to change(JournalDetail, :count).by(1)
      expect{ put :update, :id => issue, :issue => {:description => 'test1'} }.to change(JournalDetail, :count).by(1)
      expect{ put :update, :id => issue, :issue => {:description => 'test2', :due_date => User.current.today + 2.days} }.to change(JournalDetail, :count).by(2)
    end

    it 'renders reflection journals' do
      journal = FactoryGirl.create(:journal)
      issue = issues.first
      issue.easy_closed_by_id = issue.author_id
      issue.fixed_version = version
      issue.parent_id = issues.second
      issue.activity = time_entry_activity
      issue.category = issue_category
      issue.journals << journal

      reflection_columns = %w(project_id parent_id status_id tracker_id assigned_to_id priority_id category_id fixed_version_id author_id activity_id easy_closed_by_id) + issue.journalized_options[:format_detail_reflection_columns]
      reflection_columns.each do |column|
        JournalDetail.create( property: 'attr', prop_key: column, old_value: issue.try(column) , value: issue.try(column), journal: journal)
      end
      get :show, :id => issue.id, :format => :html
      expect(response).to have_http_status(200)
    end

    it 'journal to parent task when it changes' do
      expect(issue_parent1.journals.count).to eq 0
      expect(issue_parent2.journals.count).to eq 0

      expect{ post :create, :issue => { :parent_issue_id => issue_parent1.id, :project_id => project.id, :subject => 'test_journals' } }.to change(Issue, :count).by(1)
      issue_child = assigns(:issue)

      expect(issue_parent1.journals.count).to eq 1
      expect(issue_parent2.journals.count).to eq 0

      put :update, :id => issue_child, :issue => {:parent_issue_id => issue_parent2.id}

      expect(issue_parent1.journals.count).to eq 2
      expect(issue_parent2.journals.count).to eq 1
    end

  end

  context 'when update with back_url to specific filter' do
    context 'when back_url param' do
      it 'redirects to specified filter' do
        back_url = "#{issues_url}?set_filter=1&assigned_to_id=%3Dme|28"
        put :update, :id => issue, :issue => { :subject => "UPDATED" }, :back_url => back_url

        expect(response.header["Location"]).to eq(URI.escape(back_url))
      end
    end

    context 'when back_url2 param' do
      it 'redirects to specified filter' do
        back_url2 = "#{issues_url}?set_filter=1&assigned_to_id=%3Dme|28"
        put :update, :id => issue, :issue => { :subject => "UPDATED" }, :back_url2 => back_url2

        expect(response.header["Location"]).to eq(URI.escape(back_url2))
      end
    end
  end

  context 'autolinks' do
    render_views

    it 'doesnt autolink messages' do
      with_settings({'text_formatting' => 'HTML'}) do
        issue = FactoryGirl.create(:issue)
        issue.update_column(:description, "<p>message:-</p>")
        get :show, :id => issue.id
        assert_response :success
      end
    end
  end

end
