module Report
  class Measure
    def self.create_report(schools: School.all.includes(:district), academic_years: AcademicYear.all, measures: ::Measure.all, filename: "measure_report.csv")
      data = []
      mutex = Thread::Mutex.new
      data << ["Measure Name", "Measure ID", "District", "School", "School Code", "Academic Year", "Recorded Date Range", "Grades", "Student Score", "Student Zone", "Teacher Score",
               "Teacher Zone", "Admin Score", "Admin Zone", "All Score (Average)", "All Score Zone"]
      pool_size = 2
      jobs = Queue.new
      schools.each { |school| jobs << school }

      workers = pool_size.times.map do
        Thread.new do
          while school = jobs.pop(true)
            academic_years.each do |academic_year|
              measures.each do |measure|
                respondents = Respondent.by_school_and_year(school:, academic_year:)
                next if respondents.nil?

                response_rate = measure.subcategory.response_rate(school:, academic_year:)
                next unless response_rate.meets_student_threshold? || response_rate.meets_teacher_threshold?

                score = measure.score(school:, academic_year:)
                zone = measure.zone(school:, academic_year:).type.to_s.capitalize

                begin_date = SurveyItemResponse.where(school:,
                                                      academic_year:).where.not(recorded_date: nil).order(:recorded_date).first&.recorded_date&.to_date
                end_date = SurveyItemResponse.where(school:,
                                                    academic_year:).where.not(recorded_date: nil).order(:recorded_date).last&.recorded_date&.to_date
                date_range = "#{begin_date} - #{end_date}"

                row = [response_rate, measure, school, academic_year]

                all_grades = respondents.enrollment_by_grade.keys
                grades = "#{all_grades.first}-#{all_grades.last}"
                mutex.synchronize do
                  data << [measure.name,
                           measure.measure_id,
                           school.district.name,
                           school.name,
                           school.dese_id,
                           academic_year.range,
                           date_range,
                           grades,
                           student_score(row:),
                           student_zone(row:),
                           teacher_score(row:),
                           teacher_zone(row:),
                           admin_score(row:),
                           admin_zone(row:),
                           score.average,
                           zone]
                end
              end
            end
          end
        rescue ThreadError
        end
      end

      workers.each(&:join)
      FileUtils.mkdir_p Rails.root.join("tmp", "reports")
      filepath = Rails.root.join("tmp", "reports", filename)
      write_csv(data:, filepath:)
      data
    end

    def self.write_csv(data:, filepath:)
      csv = CSV.generate do |csv|
        data.each do |row|
          csv << row
        end
      end
      File.write(filepath, csv)
    end

    def self.student_score(row:)
      row in [response_rate, measure, school, academic_year]
      student_score = measure.student_score(school:, academic_year:).average if response_rate.meets_student_threshold?
      student_score || "N/A"
    end

    def self.student_zone(row:)
      row in [response_rate, measure, school, academic_year]
      if response_rate.meets_student_threshold?
        student_zone = measure.student_zone(school:,
                                            academic_year:).type.to_s.capitalize
      end

      student_zone || "N/A"
    end

    def self.teacher_score(row:)
      row in [response_rate, measure, school, academic_year]
      teacher_score = measure.teacher_score(school:, academic_year:).average if response_rate.meets_teacher_threshold?

      teacher_score || "N/A"
    end

    def self.teacher_zone(row:)
      row in [response_rate, measure, school, academic_year]
      if response_rate.meets_teacher_threshold?
        teacher_zone = measure.teacher_zone(school:, academic_year:).type.to_s.capitalize
      end

      teacher_zone || "N/A"
    end

    def self.admin_score(row:)
      row in [response_rate, measure, school, academic_year]
      admin_score = measure.admin_score(school:, academic_year:).average
      admin_score = "N/A" unless admin_score.present? && admin_score >= 0
      admin_score
    end

    def self.admin_zone(row:)
      row in [response_rate, measure, school, academic_year]
      tmp_zone = measure.admin_zone(school:, academic_year:).type
      tmp_zone == :insufficient_data ? "N/A" : tmp_zone.to_s.capitalize
    end
  end
end
