require "rails_helper"

RSpec.describe User, type: :model do
  it { is_expected.to belong_to(:casa_org) }

  it { is_expected.to have_many(:case_assignments) }
  it { is_expected.to have_many(:casa_cases).through(:case_assignments) }
  it { is_expected.to have_many(:case_contacts) }

  it { is_expected.to have_many(:supervisor_volunteers) }
  it { is_expected.to have_many(:volunteers).through(:supervisor_volunteers) }

  it { is_expected.to have_many(:followups).with_foreign_key(:creator_id) }

  it { is_expected.to have_one(:supervisor_volunteer) }
  it { is_expected.to have_one(:supervisor).through(:supervisor_volunteer) }

  it "requires display name" do
    user = build(:user, display_name: "")
    expect(user.valid?).to be false
  end

  describe "#case_contacts_for" do
    let(:volunteer) { create(:volunteer, :with_casa_cases) }
    let(:case_of_interest) { volunteer.casa_cases.first }
    let!(:contact_a) { create(:case_contact, creator: volunteer, casa_case: case_of_interest) }
    let!(:contact_b) { create(:case_contact, creator: volunteer, casa_case: volunteer.casa_cases.second) }

    it "returns all case_contacts associated with this user and the casa case id supplied" do
      sample_casa_case_id = case_of_interest.id

      result = volunteer.case_contacts_for(sample_casa_case_id)

      expect(result.length).to eq(1)
    end

    it "does not return case_contacts associated with another volunteer user" do
      other_volunteer = create(:volunteer, :with_casa_cases, casa_org: volunteer.casa_org)

      create(:case_assignment, casa_case: case_of_interest, volunteer: other_volunteer)
      create(:case_contact, creator: other_volunteer, casa_case: case_of_interest)
      create(:case_contact)

      sample_casa_case_id = case_of_interest.id

      result = volunteer.case_contacts_for(sample_casa_case_id)
      expect(result.length).to eq(1)
      result = other_volunteer.case_contacts_for(sample_casa_case_id)
      expect(result.length).to eq(1)
    end

    it "does not return case_contacts neither unassigned cases or inactive cases" do
      inactive_case_assignment = create(:case_assignment, casa_case: create(:casa_case, casa_org: volunteer.casa_org), is_active: false, volunteer: volunteer)
      case_assignment_to_inactve_case = create(:case_assignment, casa_case: create(:casa_case, active: false, casa_org: volunteer.casa_org), volunteer: volunteer)

      expect {
        volunteer.case_contacts_for(inactive_case_assignment.casa_case.id)
      }.to raise_error(ActiveRecord::RecordNotFound)

      expect {
        volunteer.case_contacts_for(case_assignment_to_inactve_case.casa_case.id)
      }.to raise_error(ActiveRecord::RecordNotFound)
    end
  end

  describe "supervisors" do
    describe "#volunteers_serving_transition_aged_youth" do
      let(:casa_org) { create(:casa_org) }
      let(:supervisor) { create(:supervisor, casa_org: casa_org) }

      it "returns the number of transition aged youth on a supervisor" do
        casa_cases = [
          create(:casa_case, casa_org: casa_org, transition_aged_youth: true),
          create(:casa_case, casa_org: casa_org, transition_aged_youth: true),
          create(:casa_case, casa_org: casa_org, transition_aged_youth: false)
        ]

        casa_cases.each do |casa_case|
          volunteer = create(:volunteer, supervisor: supervisor, casa_org: casa_org)
          volunteer.casa_cases << casa_case
        end

        expect(supervisor.volunteers_serving_transition_aged_youth).to eq(2)
      end

      it "ignores volunteers' inactive and unassgined cases" do
        volunteer = create(:volunteer, supervisor: supervisor, casa_org: casa_org)
        create(:case_assignment, casa_case: create(:casa_case, casa_org: casa_org, active: false, transition_aged_youth: true), volunteer: volunteer)
        create(:case_assignment, casa_case: create(:casa_case, casa_org: casa_org, transition_aged_youth: true), is_active: false, volunteer: volunteer)

        expect(supervisor.volunteers_serving_transition_aged_youth).to eq(0)
      end
    end

    describe "#no_contact_for_two_weeks" do
      let(:supervisor) { create(:supervisor) }

      it "returns zero for a volunteer that has successfully made contact in at least one contact_case within the last 2 weeks" do
        volunteer_1 = create(:volunteer, :with_casa_cases, supervisor: supervisor)

        case_of_interest_1 = volunteer_1.casa_cases.first
        create(:case_contact, creator: volunteer_1, casa_case: case_of_interest_1, contact_made: false, occurred_at: 1.week.ago)
        expect(supervisor.no_contact_for_two_weeks).to eq(1)
        create(:case_contact, creator: volunteer_1, casa_case: case_of_interest_1, contact_made: true, occurred_at: 1.week.ago)
        expect(supervisor.no_contact_for_two_weeks).to eq(0)
      end

      it "returns one for a volunteer that has not made any contact_cases within the last 2 weeks" do
        create(:volunteer, :with_casa_cases, supervisor: supervisor)
        expect(supervisor.no_contact_for_two_weeks).to eq(1)
      end

      it "returns zero for a volunteer that is not assigned to any casa cases" do
        create(:volunteer, supervisor: supervisor)
        expect(supervisor.no_contact_for_two_weeks).to eq(0)
      end

      it "returns one for a volunteer that has successfully made contact in at least one contact_case with occurred_at after 2 weeks" do
        volunteer_1 = create(:volunteer, :with_casa_cases, supervisor: supervisor)

        case_of_interest_1 = volunteer_1.casa_cases.first

        create(:case_contact, creator: volunteer_1, casa_case: case_of_interest_1, contact_made: true, occurred_at: 3.weeks.ago)
        expect(supervisor.no_contact_for_two_weeks).to eq(1)
      end

      it "returns zero for a volunteer that has no active casa case assignments" do
        volunteer_1 = create(:volunteer, :with_casa_cases, supervisor: supervisor)

        case_of_interest_1 = volunteer_1.casa_cases.first
        case_of_interest_2 = volunteer_1.casa_cases.last
        case_assignment_1 = case_of_interest_1.case_assignments.find_by(volunteer: volunteer_1)
        case_assignment_2 = case_of_interest_2.case_assignments.find_by(volunteer: volunteer_1)
        case_assignment_1.update!(is_active: false)
        case_assignment_2.update!(is_active: false)

        expect(supervisor.no_contact_for_two_weeks).to eq(0)
      end
    end
  end

  describe "#active_for_authentication?" do
    it "is false when the user is inactive" do
      user = create(:volunteer, :inactive)
      expect(user).not_to be_active_for_authentication
      expect(user.inactive_message).to eq(:inactive)
    end

    it "is true otherwise" do
      user = create(:volunteer)
      expect(user).to be_active_for_authentication

      user = create(:supervisor)
      expect(user).to be_active_for_authentication
    end
  end

  describe "#actively_assigned_and_active_cases" do
    let(:casa_org) { create(:casa_org) }
    let(:user) { create(:volunteer, casa_org: casa_org) }
    let!(:active_case_assignment_with_active_case) do
      create(:case_assignment, casa_case: create(:casa_case, casa_org: casa_org), volunteer: user)
    end
    let!(:active_case_assignment_with_inactive_case) do
      create(:case_assignment, casa_case: create(:casa_case, casa_org: casa_org, active: false), volunteer: user)
    end
    let!(:inactive_case_assignment_with_active_case) do
      create(:case_assignment, casa_case: create(:casa_case, casa_org: casa_org), is_active: false, volunteer: user)
    end
    let!(:inactive_case_assignment_with_inactive_case) do
      create(:case_assignment, casa_case: create(:casa_case, casa_org: casa_org, active: false), is_active: false, volunteer: user)
    end

    it "only returns the user's active cases with active case assignments" do
      expect(user.actively_assigned_and_active_cases).to match_array([active_case_assignment_with_active_case.casa_case])
    end
  end

  describe "#serving_transition_aged_youth?" do
    let(:user) { create(:volunteer) }
    let!(:case_assignment_without_transition_aged_youth) do
      create(:case_assignment, casa_case: create(:casa_case, casa_org: user.casa_org, transition_aged_youth: false), volunteer: user)
    end

    context "when the user has a transition-aged-youth case" do
      it "is true" do
        create(:case_assignment, casa_case: create(:casa_case, casa_org: user.casa_org, transition_aged_youth: true), volunteer: user)
        expect(user).to be_serving_transition_aged_youth
      end
    end

    context "when the user does not have a transition-aged-youth case" do
      it "is false" do
        expect(user).not_to be_serving_transition_aged_youth
      end
    end

    context "when the user's only transition-aged-youth case is inactive" do
      it "is false" do
        create(:case_assignment, casa_case: create(:casa_case, casa_org: user.casa_org, active: false, transition_aged_youth: true), volunteer: user)

        expect(user).not_to be_serving_transition_aged_youth
      end
    end

    context "when the user is unassigned from a transition-aged-youth case" do
      it "is false" do
        create(:case_assignment, casa_case: create(:casa_case, casa_org: user.casa_org, transition_aged_youth: true), volunteer: user, is_active: false)

        expect(user).not_to be_serving_transition_aged_youth
      end
    end
  end
end
