function sortCourse(a, b) {
  // Sort the instructor enrollments by course number then by course section
  const courseNumberA = a.coursenumber ? a.coursenumber : "";
  const courseNumberB = b.coursenumber ? b.coursenumber : "";
  const courseSectionA = a.sectioncode ? a.sectioncode : "";
  const courseSectionB = b.sectioncode ? b.sectioncode : "";
  return courseNumberA.localeCompare(courseNumberB) || courseSectionA.localeCompare(courseSectionB);
}

function getFullCourseName(item, includeSemester = false) {
  const courseSemester = includeSemester && item.semestername ? `${item.semestername} - ` : "";
  const courseNumber = item.coursenumber ? `${item.coursenumber}` : "";
  const courseName = item.coursename ? ` - ${item.coursename}` : "";
  const sectionCode = item.sectioncode ? ` - ${item.sectioncode}` : "";
  return `${courseSemester}${courseNumber}${courseName}${sectionCode}`;
}

const ReloadDataButton = (props) => {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);

  React.useEffect(() => {
    const handleClickOutside = (e) => {
      if (ref.current && !ref.current.contains(e.target)) {
        setOpen(false);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);
  
  const styles = {
    wrapper: {
      position: "relative",
      display: "inline-flex",
      marginTop: "30px"
    },
    tooltip: {
      position: "absolute",
      bottom: "100%",
      left: "50%",
      transform: "translateX(-50%)",
      marginBottom: "8px",
      background: "#333",
      color: "#fff",
      padding: "8px 10px",
      borderRadius: "4px",
      fontSize: "12px",
      whiteSpace: "normal",
      width: "120px",
      textAlign: "center",
      zIndex: 1000,
      boxShadow: "0 2px 6px rgba(0,0,0,0.3)",
    }
  };

  return (
    <div className="ps-2 margin-top-12" style={{width: "10%"}}>
      <div ref={ref} style={styles.wrapper}>
        <i
          className={"ms-Icon ms-Icon--Refresh align-middle cursor-pointer"}
          style={{fontSize: "20px"}}
          aria-label={window.altText?.refresh}
          onMouseEnter={() => setTimeout(() => {
            setOpen(true);
          }, 700)}
          onMouseLeave={() => setTimeout(() => {
            setOpen(false);
          }, 800)}
          onClick={() => {
            setOpen(false);
            props.reloadCourseData();
          }}
        />
        {open && <div style={styles.tooltip}>{window.globalLabels?.reloadCourses}</div>}
        {props.loading && (
          <div
            className="loader-wheel"
            style={{height: "25px", width: "25px", marginLeft: "8px", marginTop: "2px"}}
          />
        )}
      </div>
    </div>
  );
}

const CourseSelector = (props) => {
  const {
    selectedCourseId,
    setSelectedCourseId,
    selectedEnrollment,
    userCourseRole,
    load,
    reload,
    getTerms,
    getCourses,
    showToaster,
    showExpandedList,
    showRecentCourses,
  } = props;

  const allBlocksLabel = window.globalLabels?.allBlocks;
  const recentCoursesLabel = window.globalLabels?.recentCourses;

  const [loading, setLoading] = React.useState(false);
  const [terms, setTerms] = React.useState([]);
  const [courses, setCourses] = React.useState([]);
  const [selectedTermId, setSelectedTermId] = React.useState();

  React.useEffect(() => {
    loadData();
  }, []);

  async function loadData() {
    try {
      setLoading(true);
      await load();
      const data = getTerms();
      setTerms(data);

      const courses = getCourses();
      setCourses(courses);

      const activeRoleCache = getLocalStorageValue("UserCourseRole");
      const activeRole = activeRoleCache ?? UserCourseRole.Instructor;

      if (selectedEnrollment && activeRole === userCourseRole) {
        setSelectedTermId(selectedEnrollment.semestername);
        setSelectedCourseId(selectedEnrollment.coursesection);
      } else {
        setSelectedTermId(allBlocksLabel);
      }
      setLoading(false);

    } catch {
      showToaster(window.globalLabels?.errorLoadingCourses);
      setLoading(false);
    }
  }

  function updateTermSelection(newTerm) {
    setSelectedTermId(newTerm);

    // auto-select the first course within the selected term
    const termCourses = courses.filter(x => x.semestername === newTerm);

    if (termCourses.length > 0) {
      setSelectedCourseId(termCourses[0].coursesection);
    }
  }

  async function reloadCourseData() {
    setLoading(true);

    await reload();

    const data = getTerms();
    setTerms(data);

    const courses = getCourses();
    setCourses(courses);

    setLoading(false);
  }

  function getRecentCourses() {
    const recentLabel = {
      key: recentCoursesLabel,
      name: recentCoursesLabel
    };

    const recentCoursesCache = getLocalStorageValue("RecentObserverCourses") ?? [];

    const recentCourses = courses.filter(x => recentCoursesCache.find(y => y.courseId === x.coursesection));

    if (recentCourses.length <= 0) {
      return <></>;
    }

    return getCoursesRadioList([recentLabel], recentCourses);
  }

  function selectCourse(courseId, term) {
    if (term.key === recentCoursesLabel) {
      setSelectedTermId(allBlocksLabel);
    }

    setSelectedCourseId(courseId);
  }

  function getSelectedObserverCourseName() {
    const selectedCourse = courses.find(x => x.coursesection === selectedCourseId);
    return selectedCourse ? getFullCourseName(selectedCourse, false) : "";
  }

  function getCoursesRadioList(terms, courses) {
    return (
      <div style={{ maxHeight: "400px", overflowY: "auto"}}>
        {terms.map(sem => {
          return (
            <div>
              {((sem.key !== allBlocksLabel &&
                (sem.key === selectedTermId || allBlocksLabel === selectedTermId)) ||
                  sem.key === recentCoursesLabel) &&
                <div>
                  <div className="d-flex w-100 margin-top-15">
                    <div className="float-start crseSemTitle"><b>{sem.name}</b></div>
                    <div className="crseemptyDiv"></div>
                  </div>
                  <div className="course-list">
                    {courses
                      .filter(ie => ie.semestername === sem.key || sem.key === recentCoursesLabel)
                      .sort(sortCourse)
                      .map((item) => {
                        const courseInfo = getFullCourseName(item, sem.key === recentCoursesLabel);
                        return (
                          <div className="form-check">
                            <input
                              className="form-check-input"
                              type="radio"
                              name="courseOptions"
                              id={`${item.coursesection}`}
                              onChange={() => selectCourse(item.coursesection, sem)}
                              checked={item.coursesection === selectedCourseId}
                              value={item.coursename}
                            />
                            <label className="form-check-label" htmlFor={`${item.coursesection}`}>
                              {courseInfo}
                            </label>
                          </div>
                        )
                      })
                    }
                  </div>
                </div>
              }
            </div>
          );
        })}
      </div>
    );
  }

  return (
    <>
      <div className="displayFlex">
        <div className="margin-top-12" style={{width: "30%"}}>
          <label
            for="courseBlocks"
            className="text-muted"
          >
            {window.globalLabels.courseBlocks}
          </label>
          <SearchSelect
            options={terms.map(item => { return { value: item.key, label: item.name } })}
            value={selectedTermId ?? ""}
            onChange={(newTerm) => updateTermSelection(newTerm)}
            hideSearch
          />
        </div>
        <div className="ps-2 margin-top-12" style={{width: "60%"}}>
          <label className="text-muted">{window.globalLabels?.courses}</label>
          <SearchSelect
            options={
              courses
                .filter(ie => ie.semestername === selectedTermId || selectedTermId === allBlocksLabel)
                .sort(sortCourse)
                .map((item) => {
                  return {
                    value: item.coursesection,
                    label: getFullCourseName(item, selectedTermId === allBlocksLabel),
                  };
                }
              )}
            value={selectedCourseId}
            onChange={(newCourse) => setSelectedCourseId(newCourse)}
          />
        </div>
        <ReloadDataButton loading={loading} reloadCourseData={reloadCourseData} />
      </div>
      {showRecentCourses && getRecentCourses()}
      {showExpandedList && getCoursesRadioList(terms, courses)}
      <div style={{
        position: "absolute",
        bottom: "-47px",
        width: "525px",
        overflow: "hidden",
        whiteSpace: "nowrap",
        textOverflow: "ellipsis"
      }}>
        <b>{window.globalLabels?.course}:</b> {courses && getSelectedObserverCourseName()}
      </div>
    </>
  );
}

const CourseSelectionModal = (props) => {
  const {
    showModal,
    onClose,
    selectedEnrollment,
    updateSelectedCourse,
    showToaster,
    IMS_InstructorObserverRoleEnabled
  } = props;

  const [activeTab, setActiveTab] = React.useState("instructor");
  const [selectedCourseId, setSelectedCourseId] = React.useState(selectedEnrollment.coursesection ?? "-1");

  React.useEffect(() => {
    const activeRoleCache = getLocalStorageValue("UserCourseRole");
    const activeRole = activeRoleCache ?? UserCourseRole.Instructor;

    setActiveTab(
      activeRole === UserCourseRole.Observer && IMS_InstructorObserverRoleEnabled
        ? "observer"
        : "instructor");
  }, []);

  function submitCourseSelection() {
    const courses = activeTab === "instructor"
      ? EnrollmentDataStore.getInstructorCourses()
      : EnrollmentDataStore.getObserverCourses();

    const selectedCourse = courses.find(x => x.coursesection === selectedCourseId);
    const activeRole = activeTab === "instructor" ? UserCourseRole.Instructor : UserCourseRole.Observer;

    updateRecentCourses();
    updateSelectedCourse(selectedCourse, activeRole);
  }

  function updateRecentCourses() {
    if (activeTab !== "observer") {
      return;
    }

    const recentCourses = getLocalStorageValue("RecentObserverCourses") ?? [];
    const existingCourse = recentCourses.find(x => x.courseId === selectedCourseId);

    if (recentCourses.length >= 5 && !existingCourse) {
      recentCourses.sort(
        (a, b) => new Date(a.lastVisited) - new Date(b.lastVisited)
      ).shift();
    }

    if (!existingCourse) {
      recentCourses.unshift({
        courseId: selectedCourseId,
        lastVisited: new Date(),
      });
    } else {
      existingCourse.lastVisited = new Date();
    }

    // keep recent courses for a week, otherwise let them expire if they're not updated.
    setLocalStorage(recentCourses, true, "RecentObserverCourses", 10080);
  }

  return (
    <Modal
      show={showModal}
      id="courseModal"
      title={window.globalLabels?.changeCourse}
      modalSize="large"
      onClose={onClose}
      closeLabel={window.globalLabels?.cancel}
      onSave={() => submitCourseSelection()}
      saveLabel={activeTab === "instructor"
        ? window.globalLabels?.instructCourse
        : window.globalLabels?.observeCourse
      }
    >
      <Pivot
        selectedKey={activeTab}
        onChange={setActiveTab}
      >
        <PivotItem
          headerText={window.globalLabels?.instructor}
          itemKey="instructor"
        >
          <CourseSelector
            selectedCourseId={selectedCourseId}
            setSelectedCourseId={setSelectedCourseId}
            selectedEnrollment={selectedEnrollment}
            userCourseRole={UserCourseRole.Instructor}
            load={async () => await EnrollmentDataStore.getInstructorEnrollments()}
            reload={async () => await EnrollmentDataStore.loadInstructorEnrollments()}
            getTerms={() => EnrollmentDataStore.getInstructorTerms()}
            getCourses={() => EnrollmentDataStore.getInstructorCourses()}
            showToaster={showToaster}
            showExpandedList
          />
        </PivotItem>
        <PivotItem
          headerText={window.globalLabels?.observer}
          itemKey="observer"
          hidden={!IMS_InstructorObserverRoleEnabled}
        >
          <CourseSelector
            selectedCourseId={selectedCourseId}
            setSelectedCourseId={setSelectedCourseId}
            selectedEnrollment={selectedEnrollment}
            userCourseRole={UserCourseRole.Observer}
            load={async () => await EnrollmentDataStore.getObserverEnrollments()}
            reload={async () => await EnrollmentDataStore.loadObserverEnrollments()}
            getTerms={() => EnrollmentDataStore.getObserverTerms()}
            getCourses={() => EnrollmentDataStore.getObserverCourses()}
            showToaster={showToaster}
            showRecentCourses
          />
        </PivotItem>
      </Pivot>
    </Modal>
  );
}

window.CourseSelectionModal = CourseSelectionModal;