require 'spec_helper'

RSpec.describe SchoolCalendarEventDays, type: :service do
  let!(:school_calendars) {
    create_list(
      :school_calendar,
      2,
      :with_trimester_steps
    )
  }
  let(:list_classrooms) { create_list(:classroom, 3, unity: school_calendars.first.unity, period: Periods::MATUTINAL) }
  let(:list_classroom_grades) {
    list_classrooms.map do |classroom|
      create(
        :classrooms_grade,
        classroom: classroom,
      )
    end
  }
  let!(:classroom_grades_with_grade) {
    create(
      :classrooms_grade,
      classroom: list_classrooms.second,
      grade: list_classroom_grades.last.grade
    )
  }

  describe 'when to delete daily_frequencies' do
    context 'with coverage "by_grade" and event_type "extra_school_event_without_frequency"' do
      let!(:school_calendar_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.first,
          coverage: 'by_grade',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::EXTRA_SCHOOL_WITHOUT_FREQUENCY,
          grade_id: list_classroom_grades.first.grade_id,
          course_id: list_classroom_grades.first.grade.course_id,
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-10',
          end_date: '2017-02-16'
        )
      }
      let!(:daily_frequency) {
        create(
          :daily_frequency,
          classroom: list_classrooms.first,
          frequency_date: '2017-02-15',
          unity: list_classrooms.first.unity,
          school_calendar: school_calendars.first,
          period: Periods::MATUTINAL
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.first],
          [school_calendar_event],
          'create',
          '2017-02-10',
          '2017-02-16'
        )
      end

      it 'delete only the daily_frequency in the grade' do
        expect { subject }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
      end
    end

    context 'with coverage "by_unity" and event_type "extra_school_event_without_frequency"' do
      let(:list_classrooms_for_unity) { create_list(:classroom, 3, unity: school_calendars.last.unity, period: Periods::MATUTINAL) }
      let(:classroom_grades) {
        list_classrooms_for_unity.map do |classroom|
          create(
            :classrooms_grade,
            classroom: classroom,
          )
        end
      }
      let!(:school_calendar_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_unity',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::EXTRA_SCHOOL_WITHOUT_FREQUENCY,
          grade_id: '',
          course_id: '',
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-10',
          end_date: '2017-02-16'
        )
      }

      let!(:daily_frequency) {
        create(
          :daily_frequency,
          id: 456,
          classroom: list_classrooms_for_unity.first,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::MATUTINAL
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.last],
          [school_calendar_event],
          'create',
          '2017-02-10',
          '2017-02-16'
        )
      end

      it 'delete only the daily_frequency in the unity' do
        expect { subject }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
      end
    end

    context 'with coverage "by_classroom" and event_type "extra_school_event_without_frequency"' do
      let!(:school_calendar_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.first,
          coverage: 'by_classroom',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::EXTRA_SCHOOL_WITHOUT_FREQUENCY,
          grade_id: list_classroom_grades.last.grade_id,
          course_id: list_classroom_grades.last.grade.course_id,
          classroom_id: list_classrooms.second.id,
          show_in_frequency_record: false,
          start_date: '2017-02-10',
          end_date: '2017-02-16'
        )
      }
      let!(:daily_frequency) {
        create(
          :daily_frequency,
          classroom: list_classrooms.second,
          frequency_date: '2017-02-15',
          unity: list_classrooms.second.unity,
          school_calendar: school_calendars.first,
          period: Periods::MATUTINAL
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.first],
          [school_calendar_event],
          'create',
          '2017-02-10',
          '2017-02-16'
        )
      end

      it 'delete only the daily_frequency in the classroom' do
        expect { subject }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
      end
    end

    context 'with coverage "by_course" and event_type "extra_school_event_without_frequency"' do
      let!(:grade_with_course) {
        create(
          :grade,
          course: list_classroom_grades.last.grade.course
        )
      }
      let!(:school_calendar_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.first,
          coverage: 'by_course',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::EXTRA_SCHOOL_WITHOUT_FREQUENCY,
          grade_id: '',
          course_id: grade_with_course.course_id,
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-10',
          end_date: '2017-02-16'
        )
      }
      let!(:daily_frequency) {
        create(
          :daily_frequency,
          classroom: list_classroom_grades.last.classroom,
          frequency_date: '2017-02-15',
          unity: list_classroom_grades.last.classroom.unity,
          school_calendar: school_calendars.first,
          period: Periods::MATUTINAL
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.first],
          [school_calendar_event],
          'create',
          '2017-02-10',
          '2017-02-16'
        )
      end

      it 'delete only the daily_frequency in the course' do
        expect { subject }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
      end
    end
  end

  describe 'when the event_type_changed parameter is true' do
    let!(:list_classrooms_for_unity) { create_list(:classroom, 3, unity: school_calendars.last.unity, period: Periods::MATUTINAL) }
    let!(:classroom_grades) {
      list_classrooms_for_unity.map do |classroom|
        create(
          :classrooms_grade,
          classroom: classroom,
        )
      end
    }
    let!(:daily_frequency) {
      create(
        :daily_frequency,
        id: 456,
        classroom: list_classrooms_for_unity.first,
        frequency_date: '2017-02-15',
        unity: school_calendars.last.unity,
        school_calendar: school_calendars.last,
        period: Periods::MATUTINAL
      )
    }
    let!(:unity_school_day) {
      create(
        :unity_school_day,
        unity: school_calendars.last.unity,
        school_day: '2017-02-15'
      )
    }

    subject do
      SchoolCalendarEventDays.update_school_days(
        [school_calendars.last],
        [school_calendar_event],
        'create',
        '2017-02-10',
        '2017-02-16',
        true
      )
    end

    context 'when the event is EventTypes::NO_SCHOOL' do
      let!(:school_calendar_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_unity',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: '',
          course_id: '',
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-10',
          end_date: '2017-02-16'
        )
      }

      it 'deletes the attendance and unity_school_day' do
        expect {
          subject
        }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
         .and change { UnitySchoolDay.where(id: unity_school_day.id).count }.by(-1)
      end
    end

    context 'when the event is EventTypes::EXTRA_SCHOOL_WITHOUT_FREQUENCY' do
      let!(:school_calendar_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_unity',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::EXTRA_SCHOOL_WITHOUT_FREQUENCY,
          grade_id: '',
          course_id: '',
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-10',
          end_date: '2017-02-16'
        )
      }

      it 'deletes only the attendance and not the unity_school_day' do
        expect {
          subject
        }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
        .and change {
          UnitySchoolDay.where(unity_id: school_calendars.last.unity, school_day: '2017-02-15').count
        }.by(0)
      end
    end

    context 'when the event is edited to NO_SCHOOL' do
      let!(:school_calendar_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_unity',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: '',
          course_id: '',
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-10',
          end_date: '2017-02-16'
        )
      }
      let!(:daily_frequency) {
        create(
          :daily_frequency,
          classroom: list_classrooms_for_unity.first,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::MATUTINAL
        )
      }
      let!(:unity_school_day) {
        create(
          :unity_school_day,
          unity: school_calendars.last.unity,
          school_day: '2017-02-15'
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.last],
          [school_calendar_event],
          'update',
          '2017-02-10',
          '2017-02-16',
          true
        )
      end

      it 'deletes the attendance and unity_school_day when changing to NO_SCHOOL' do
        expect {
          subject
        }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
         .and change { UnitySchoolDay.where(id: unity_school_day.id).count }.by(-1)
      end
    end
  end

  describe 'when creating NO_SCHOOL event with existing event on same date' do
    let!(:list_classrooms_for_unity) { create_list(:classroom, 3, unity: school_calendars.last.unity, period: Periods::MATUTINAL) }
    let!(:classroom_grades) {
      list_classrooms_for_unity.map do |classroom|
        create(:classrooms_grade, classroom: classroom)
      end
    }

    context 'when by_classroom event already exists and creating by_unity NO_SCHOOL event' do
      let!(:existing_event) {
        create(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_classroom',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: classroom_grades.first.grade_id,
          course_id: classroom_grades.first.grade.course_id,
          classroom_id: list_classrooms_for_unity.first.id,
          show_in_frequency_record: false,
          start_date: '2017-02-15',
          end_date: '2017-02-15'
        )
      }
      let!(:new_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_unity',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: '',
          course_id: '',
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-15',
          end_date: '2017-02-15'
        )
      }
      let!(:daily_frequency) {
        create(
          :daily_frequency,
          classroom: list_classrooms_for_unity.second,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::MATUTINAL
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.last],
          [new_event],
          'create',
          '2017-02-15',
          '2017-02-15'
        )
      end

      it 'deletes daily_frequency even when another event exists on the same date' do
        expect { subject }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
      end
    end

    context 'when by_grade event already exists and creating by_unity NO_SCHOOL event' do
      let!(:existing_event) {
        create(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_grade',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: classroom_grades.first.grade_id,
          course_id: classroom_grades.first.grade.course_id,
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-15',
          end_date: '2017-02-15'
        )
      }
      let!(:new_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_unity',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: '',
          course_id: '',
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-15',
          end_date: '2017-02-15'
        )
      }
      let!(:daily_frequency) {
        create(
          :daily_frequency,
          classroom: list_classrooms_for_unity.second,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::MATUTINAL
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.last],
          [new_event],
          'create',
          '2017-02-15',
          '2017-02-15'
        )
      end

      it 'deletes daily_frequency even when another event exists on the same date' do
        expect { subject }.to change { DailyFrequency.where(id: daily_frequency.id).count }.by(-1)
      end
    end
  end

  describe 'when creating NO_SCHOOL event with specific period' do
    let!(:matutinal_classroom) {
      create(:classroom, unity: school_calendars.last.unity, period: Periods::MATUTINAL)
    }
    let!(:vespertine_classroom) {
      create(:classroom, unity: school_calendars.last.unity, period: Periods::VESPERTINE)
    }
    let!(:matutinal_classroom_grade) {
      create(:classrooms_grade, classroom: matutinal_classroom)
    }
    let!(:vespertine_classroom_grade) {
      create(:classrooms_grade, classroom: vespertine_classroom)
    }

    context 'when by_unity event has specific period defined' do
      let!(:matutinal_frequency) {
        create(
          :daily_frequency,
          classroom: matutinal_classroom,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::MATUTINAL
        )
      }
      let!(:vespertine_frequency) {
        create(
          :daily_frequency,
          classroom: vespertine_classroom,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::VESPERTINE
        )
      }
      let!(:new_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_unity',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: '',
          course_id: '',
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-15',
          end_date: '2017-02-15'
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.last],
          [new_event],
          'create',
          '2017-02-15',
          '2017-02-15'
        )
      end

      it 'deletes only matutinal daily_frequency' do
        expect { subject }.to change { DailyFrequency.where(id: matutinal_frequency.id).count }.by(-1)
      end

      it 'does not delete vespertine daily_frequency' do
        expect { subject }.not_to change { DailyFrequency.where(id: vespertine_frequency.id).count }
      end
    end

    context 'when by_grade event has specific period defined' do
      let!(:matutinal_frequency) {
        create(
          :daily_frequency,
          classroom: matutinal_classroom,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::MATUTINAL
        )
      }
      let!(:vespertine_frequency) {
        create(
          :daily_frequency,
          classroom: vespertine_classroom,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::VESPERTINE
        )
      }
      let!(:new_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_grade',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: matutinal_classroom_grade.grade_id,
          course_id: matutinal_classroom_grade.grade.course_id,
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-15',
          end_date: '2017-02-15'
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.last],
          [new_event],
          'create',
          '2017-02-15',
          '2017-02-15'
        )
      end

      it 'deletes only matutinal daily_frequency from matching grade' do
        expect { subject }.to change { DailyFrequency.where(id: matutinal_frequency.id).count }.by(-1)
      end

      it 'does not delete vespertine daily_frequency' do
        expect { subject }.not_to change { DailyFrequency.where(id: vespertine_frequency.id).count }
      end
    end

    context 'when by_course event has specific period defined' do
      let!(:matutinal_frequency) {
        create(
          :daily_frequency,
          classroom: matutinal_classroom,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::MATUTINAL
        )
      }
      let!(:vespertine_frequency) {
        create(
          :daily_frequency,
          classroom: vespertine_classroom,
          frequency_date: '2017-02-15',
          unity: school_calendars.last.unity,
          school_calendar: school_calendars.last,
          period: Periods::VESPERTINE
        )
      }
      let!(:new_event) {
        build(
          :school_calendar_event,
          school_calendar: school_calendars.last,
          coverage: 'by_course',
          periods: Periods::MATUTINAL,
          event_type: EventTypes::NO_SCHOOL,
          grade_id: '',
          course_id: matutinal_classroom_grade.grade.course_id,
          classroom_id: '',
          show_in_frequency_record: false,
          start_date: '2017-02-15',
          end_date: '2017-02-15'
        )
      }

      subject do
        SchoolCalendarEventDays.update_school_days(
          [school_calendars.last],
          [new_event],
          'create',
          '2017-02-15',
          '2017-02-15'
        )
      end

      it 'deletes only matutinal daily_frequency from matching course' do
        expect { subject }.to change { DailyFrequency.where(id: matutinal_frequency.id).count }.by(-1)
      end

      it 'does not delete vespertine daily_frequency' do
        expect { subject }.not_to change { DailyFrequency.where(id: vespertine_frequency.id).count }
      end
    end
  end
end
