import type {
  GlitchSlide,
  LectureDefinition,
  Slide,
  VideoSegment
} from "../types/lecture";
import type { ViewportMode } from "../types/player";

export function clampGlobalTime(value: number, durationSec: number) {
  return Math.min(durationSec, Math.max(0, value));
}

export function getActiveSegment(
  segments: VideoSegment[],
  globalTimeSec: number
): VideoSegment | null {
  for (const segment of segments) {
    if (
      globalTimeSec >= segment.startTimeSec &&
      globalTimeSec < segment.startTimeSec + segment.durationSec
    ) {
      return segment;
    }
  }

  return segments[segments.length - 1] ?? null;
}

export function getNextSegment(
  segments: VideoSegment[],
  segmentId: string
): VideoSegment | null {
  const index = segments.findIndex((segment) => segment.id === segmentId);
  if (index === -1) {
    return null;
  }

  return segments[index + 1] ?? null;
}

export function getLocalTimeWithinSegment(
  segment: VideoSegment,
  globalTimeSec: number
) {
  return Math.min(
    segment.durationSec,
    Math.max(0, globalTimeSec - segment.startTimeSec)
  );
}

export function getSlideEndTime(
  slides: Slide[],
  currentSlideId: string,
  lectureDurationSec: number
) {
  const index = slides.findIndex((slide) => slide.id === currentSlideId);
  if (index === -1) {
    return lectureDurationSec;
  }

  const currentSlide = slides[index];
  if (currentSlide.endTimeSec != null) {
    return currentSlide.endTimeSec;
  }

  return slides[index + 1]?.startTimeSec ?? lectureDurationSec;
}

export function getActiveSlide(
  slides: Slide[],
  globalTimeSec: number,
  lectureDurationSec: number
): Slide | null {
  for (const slide of slides) {
    if (slide.startTimeSec == null) {
      continue;
    }

    const endTimeSec = getSlideEndTime(slides, slide.id, lectureDurationSec);
    if (globalTimeSec >= slide.startTimeSec && globalTimeSec < endTimeSec) {
      return slide;
    }
  }

  return null;
}

export function getDefaultGlitchSlide(slide: Slide): GlitchSlide {
  const sorted = [...slide.glitchSlides].sort((left, right) => right.score - left.score);
  return sorted[0];
}

export function getCompatibleGlitchSlides(
  slide: Slide,
  viewportMode: ViewportMode
): GlitchSlide[] {
  const exactMatches = slide.glitchSlides.filter(
    (candidate) => candidate.orientation === viewportMode
  );

  if (exactMatches.length > 0) {
    return exactMatches;
  }

  const genericMatches = slide.glitchSlides.filter(
    (candidate) => !candidate.orientation || candidate.orientation === "any"
  );

  return genericMatches.length > 0 ? genericMatches : slide.glitchSlides;
}

export function getActiveGlitchSlide(
  slide: Slide,
  viewportMode: ViewportMode,
  overrideGlitchSlideId?: string
): GlitchSlide {
  const compatibleCandidates = getCompatibleGlitchSlides(slide, viewportMode);

  if (overrideGlitchSlideId) {
    const overrideCandidate = compatibleCandidates.find(
      (candidate) => candidate.id === overrideGlitchSlideId
    );
    if (overrideCandidate) {
      return overrideCandidate;
    }
  }

  const sorted = [...compatibleCandidates].sort(
    (left, right) => right.score - left.score
  );
  return sorted[0];
}

export function getUpcomingSlides(
  slides: Slide[],
  globalTimeSec: number,
  lectureDurationSec: number,
  limit: number
) {
  const activeSlide = getActiveSlide(slides, globalTimeSec, lectureDurationSec);
  const activeIndex = activeSlide
    ? slides.findIndex((slide) => slide.id === activeSlide.id)
    : -1;

  return slides.slice(activeIndex + 1, activeIndex + 1 + limit);
}

export function getInitialLectureState(lecture: LectureDefinition) {
  const activeSegment = getActiveSegment(lecture.segments, 0);
  const activeSlide = getActiveSlide(lecture.slides, 0, lecture.durationSec);

  return {
    globalTimeSec: 0,
    activeSegmentId: activeSegment?.id ?? null,
    activeSlideId: activeSlide?.id ?? null
  };
}
