import { itGetCached, itPost } from "@/fetchHelpers";
import { deleteCircleDocument } from "@/services/files";
import type {
  CircleDocument,
  CourseSession,
  CourseSessionAssignmentDetails,
  CourseSessionAttendanceCourse,
  CourseSessionUser,
  ExpertSessionUser,
} from "@/types";
import eventBus from "@/utils/eventBus";
import { useLocalStorage } from "@vueuse/core";
import uniqBy from "lodash/uniqBy";
import log from "loglevel";
import { defineStore } from "pinia";
import { computed, ref } from "vue";
import { useCircleStore } from "./circle";
import { useUserStore } from "./user";

const SELECTED_COURSE_SESSIONS_KEY = "selectedCourseSessionMap";

export const useCourseSessionsStore = defineStore("courseSessions", () => {
  const loaded = ref(false);
  const allCourseSessions = ref<CourseSession[]>([]);

  async function loadCourseSessionsData(reload = false) {
    log.debug("loadCourseSessionsData called");

    allCourseSessions.value = await itGetCached(`/api/course/sessions/`, {
      reload: reload,
    });

    const userStore = useUserStore();
    if (userStore.loggedIn) {
      // TODO: refactor after implementing of Klassenkonzept
      await Promise.all(
        allCourseSessions.value.map(async (cs) => {
          const users = (await itGetCached(`/api/course/sessions/${cs.id}/users/`, {
            reload: reload,
          })) as CourseSessionUser[];
          cs.users = users;
        })
      );

      if (!allCourseSessions.value) {
        throw `No courseSessionData found for user`;
      }
    }

    loaded.value = true;
  }

  const selectedCourseSessionMap = useLocalStorage(
    SELECTED_COURSE_SESSIONS_KEY,
    new Map<string, number>()
  );

  const _currentCourseSlug = ref("");

  const uniqueCourseSessionsByCourse = computed(() =>
    // Im Dashboard wird aktuell ein Widget pro Kurs dargestellt
    // mit dem Fortschritt jeweils einer Durchführung.
    // Dieser Getter wird nur dort benutzt.
    // TODO: Das Dashboard verschwindet evtl. in Zukunft, dann kann dieser Getter weg.
    // @ts-ignore
    uniqBy(allCourseSessions.value, "course.id")
  );

  function selectedCourseSessionForCourse(courseSlug: string) {
    // Wir wollen pro Kurs wissen, welche Durchführung der User zuletzt ausgewählt hat.
    // Die letzte Durchführung wird im localStorage via `selectedCoruseSessionMap`
    // gespeichert und hier geladen.
    // Wenn noch keine Durchführung ausgewählt wurde, wird die erste Durchführung
    // in `courseSessionForCourse` zurückgegeben.
    try {
      const courseSessionId = selectedCourseSessionMap.value.get(courseSlug);
      if (courseSessionId) {
        return allCourseSessions.value.find((cs) => {
          return cs.id === courseSessionId;
        });
      }
    } catch (e) {
      log.error("Error while parsing courseSessions from localStorage", e);
    }

    // Keine Durchführung ausgewählt im localStorage
    return undefined;
  }

  function switchCourseSession(courseSession: CourseSession) {
    log.debug("switchCourseSession", courseSession);
    selectedCourseSessionMap.value.set(courseSession.course.slug, courseSession.id);
    // Emit event so that the App can re-render with the new courseSession
    eventBus.emit("switchedCourseSession", courseSession.id);
  }

  function courseSessionForCourse(courseSlug: string) {
    if (courseSlug) {
      const courseSession = selectedCourseSessionForCourse(courseSlug);
      if (courseSession) {
        return courseSession;
      } else {
        // return first if there is no selected courseSession
        return allCourseSessions.value.find((cs) => {
          return cs.course.slug === courseSlug;
        });
      }
    }

    return undefined;
  }

  function allCourseSessionsForCourse(courseSlug: string) {
    return allCourseSessions.value.filter((cs) => {
      return cs.course.slug === courseSlug;
    });
  }

  const currentCourseSession = computed(() => {
    return courseSessionForCourse(_currentCourseSlug.value);
  });

  const allCurrentCourseSessions = computed(() => {
    return allCourseSessionsForCourse(_currentCourseSlug.value);
  });

  const currentCourseSessionHasCockpit = computed(() => {
    if (currentCourseSession.value) {
      return hasCockpit(currentCourseSession.value);
    }

    return false;
  });

  const circleExperts = computed(() => {
    const circleStore = useCircleStore();
    const circleTranslationKey = circleStore.circle?.translation_key;

    if (currentCourseSession.value && circleTranslationKey) {
      return currentCourseSession.value.users.filter((u) => {
        if (u.role === "EXPERT") {
          return (u as ExpertSessionUser).circles
            .map((c) => c.translation_key)
            .includes(circleTranslationKey);
        }
        return false;
      }) as ExpertSessionUser[];
    }
    return [];
  });

  const canUploadCircleDocuments = computed(() => {
    const userStore = useUserStore();
    return (
      circleExperts.value.filter((expert) => expert.user_id === userStore.id).length > 0
    );
  });

  const circleDocuments = computed(() => {
    const circleStore = useCircleStore();

    return (
      circleStore.circle?.learningSequences
        .map((ls) => ({ id: ls.id, title: ls.title, documents: [] }))
        .map((ls: { id: number; title: string; documents: CircleDocument[] }) => {
          if (currentCourseSession.value === undefined) {
            return ls;
          }

          for (const document of currentCourseSession.value.documents) {
            if (document.learning_sequence === ls.id) {
              ls.documents.push(document);
            }
          }
          return ls;
        })
        .filter((ls) => ls.documents.length > 0) || []
    );
  });

  function hasCockpit(couseSession: CourseSession) {
    const userStore = useUserStore();
    return (
      userStore.course_session_experts.includes(couseSession.id) ||
      userStore.is_superuser
    );
  }

  function addDocument(document: CircleDocument) {
    currentCourseSession.value?.documents.push(document);
  }

  async function startUpload() {
    log.debug("loadCourseSessionsData called");
    allCourseSessions.value = await itPost(`/api/core/file/start`, {
      file_type: "image/png",
      file_name: "test.png",
    });
  }

  async function removeDocument(documentId: number) {
    await deleteCircleDocument(documentId);

    if (currentCourseSession.value === undefined) {
      return;
    }

    currentCourseSession.value.documents = currentCourseSession.value?.documents.filter(
      (d) => d.id !== documentId
    );
  }

  function findAttendanceCourse(
    contentId: number
  ): CourseSessionAttendanceCourse | undefined {
    if (currentCourseSession.value) {
      return currentCourseSession.value.attendance_courses.find(
        (attendanceCourse) => attendanceCourse.learningContentId === contentId
      );
    }
  }

  function findAssignmentDetails(
    contentId?: number
  ): CourseSessionAssignmentDetails | undefined {
    if (contentId && currentCourseSession.value) {
      return currentCourseSession.value.assignment_details_list.find(
        (assignmentDetails) => assignmentDetails.learningContentId === contentId
      );
    }
  }

  return {
    uniqueCourseSessionsByCourse,
    allCurrentCourseSessions,
    courseSessionForCourse,
    switchCourseSession,
    hasCockpit,
    currentCourseSessionHasCockpit,
    canUploadCircleDocuments,
    circleDocuments,
    circleExperts,
    addDocument,
    startUpload,
    removeDocument,
    findAttendanceCourse,
    findAssignmentDetails,

    // use `useCurrentCourseSession` whenever possible
    currentCourseSession,

    loadCourseSessionsData,
    loaded,
    // only used so that `router.afterEach` can switch it
    _currentCourseSlug,

    // only used for unit testing
    allCourseSessions,
  };
});
