import orderBy from "lodash/orderBy";

import { Circle } from "@/services/circle";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useLearningPathStore } from "@/stores/learningPath";
import type {
  Course,
  CourseCompletion,
  LearningContentInterface,
  LearningPathChild,
  Topic,
  WagtailLearningPath,
} from "@/types";

export interface ContinueData {
  url: string;
  has_no_progress: boolean;
}

function getLastCompleted(courseSlug: string, completionData: CourseCompletion[]) {
  if (completionData.length === 0) {
    return undefined;
  }
  const courseSessionsStore = useCourseSessionsStore();
  const courseSession = courseSessionsStore.courseSessionForCourse(courseSlug);
  return orderBy(completionData, ["updated_at"], "desc").find((c: CourseCompletion) => {
    return (
      c.completion_status === "success" &&
      c.course_session === courseSession?.id &&
      c.page_type.startsWith("learnpath.LearningContent")
    );
  });
}

export class LearningPath implements WagtailLearningPath {
  readonly content_type = "learnpath.LearningPath";
  public topics: Topic[];
  public circles: Circle[];
  public nextLearningContent?: LearningContentInterface;

  public static fromJson(
    json: WagtailLearningPath,
    completionData: CourseCompletion[],
    userId: number | undefined
  ): LearningPath {
    return new LearningPath(
      json.id,
      json.slug,
      json.course.title,
      json.translation_key,
      json.frontend_url,
      json.course,
      json.children,
      userId,
      completionData
    );
  }

  constructor(
    public readonly id: number,
    public readonly slug: string,
    public readonly title: string,
    public readonly translation_key: string,
    public readonly frontend_url: string,
    public readonly course: Course,
    public children: LearningPathChild[],
    public userId: number | undefined,
    completionData?: CourseCompletion[]
  ) {
    // parse children
    this.topics = [];
    this.circles = [];

    let topic: Topic | undefined;

    this.children.forEach((page) => {
      if (page.content_type === "learnpath.Topic") {
        if (topic) {
          this.topics.push(topic);
        }
        topic = Object.assign(page, { circles: [] });
      }
      if (page.content_type === "learnpath.Circle") {
        const circle = Circle.fromJson(page, this);
        if (completionData && completionData.length > 0) {
          circle.parseCompletionData(completionData);
        }
        if (topic) {
          topic.circles.push(circle);
        }

        circle.previousCircle = this.circles[this.circles.length - 1];
        if (circle.previousCircle) {
          circle.previousCircle.nextCircle = circle;
        }
        this.circles.push(circle);
      }
    });

    if (topic) {
      this.topics.push(topic);
    }

    if (completionData) {
      this.calcNextLearningContent(completionData);
    }
  }

  public async reloadCompletionData() {
    const learningPathStore = useLearningPathStore();
    const completionData = await learningPathStore.loadCourseSessionCompletionData(
      this.course.slug,
      this.userId
    );
    for (const circle of this.circles) {
      circle.parseCompletionData(completionData);
    }
  }

  public calcNextLearningContent(completionData: CourseCompletion[]): void {
    this.nextLearningContent = undefined;

    const lastCompletedLearningContent = getLastCompleted(
      this.course.slug,
      completionData
    );

    if (lastCompletedLearningContent) {
      const lastCircle = this.circles.find((circle) => {
        return circle.flatLearningContents.find(
          (learningContent) =>
            learningContent.translation_key === lastCompletedLearningContent.page_key
        );
      });
      if (lastCircle) {
        const lastLearningContent = lastCircle.flatLearningContents.find(
          (learningContent) =>
            learningContent.translation_key === lastCompletedLearningContent.page_key
        );
        if (lastLearningContent && lastLearningContent.nextLearningContent) {
          this.nextLearningContent = lastLearningContent.nextLearningContent;
        } else {
          if (lastCircle.nextCircle) {
            this.nextLearningContent = lastCircle.nextCircle.flatLearningContents[0];
          }
        }
      }
    } else {
      if (this.circles[0]) {
        this.nextLearningContent = this.circles[0].flatLearningContents[0];
      }
    }
  }

  public get continueData(): ContinueData {
    if (this.nextLearningContent) {
      const circle = this.nextLearningContent.parentCircle;
      const url =
        this.nextLearningContent.parentLearningSequence?.frontend_url ||
        circle.frontend_url;
      const isFirst =
        this.nextLearningContent.translation_key ===
        this.circles[0].flatLearningContents[0].translation_key;
      return {
        url,
        has_no_progress: isFirst,
      };
    }

    return {
      url: "",
      has_no_progress: true,
    };
  }
}
