import { useEffect, useRef } from 'react';

import { ContextType } from '@/logging/contextTypes';
import { Clip } from '@/state/clipStore';

import { useStores } from '../AppProviders';
import { useChatStore } from './stores';
import { parsePartialMessage } from './utils';

const isPlayableClip = (clip: Clip) => {
  return (
    clip &&
    (clip.status === 'streaming' || clip.status === 'complete') &&
    !clip.is_trashed
  );
};

export const useSyncQueueWithMessages = (messages: any[]) => {
  const { queue, clips } = useStores();
  const { chatUUID } = useChatStore();
  const messageClipIds: string[] = [];
  const cachedClipIndexes = useRef<any>(null);
  const clipsIndexes: Record<number, number> = {};
  let currentIndex = 0;

  messages.forEach((message) => {
    const parsedPartial: any = parsePartialMessage(message);
    if (!!parsedPartial?.clipIds) {
      messageClipIds.push(
        ...parsedPartial.clipIds.filter((id: string) =>
          isPlayableClip(clips.clipById[id])
        )
      );
    } else if (!!parsedPartial?.parsed_content?.clipIds) {
      messageClipIds.push(
        ...parsedPartial.parsed_content.clipIds.filter((id: string) =>
          isPlayableClip(clips.clipById[id])
        )
      );
    } else if (!!parsedPartial?.parsed_content?.result) {
      const resultClipIds = (
        parsedPartial.parsed_content.result?.['']?.result ?? []
      ).map((result: any) => result.id);
      messageClipIds.push(
        ...resultClipIds.filter((id: string) =>
          isPlayableClip(clips.clipById[id])
        )
      );
    }
  });

  messages.forEach((message, msgIndex: number) => {
    const parsedPartial: any = parsePartialMessage(message);
    if (!!parsedPartial?.parsed_content?.result) {
      const clipIds = (parsedPartial.parsed_content.result?.['']?.result ?? [])
        .map((result: any) => result.id)
        .filter((id: string) => isPlayableClip(clips.clipById[id]));
      if (clipIds.length > 0) {
        clipsIndexes[msgIndex] = currentIndex;
        currentIndex += clipIds.length;
      }
    } else if (!!parsedPartial?.clipIds) {
      clipsIndexes[msgIndex] = currentIndex;
      currentIndex += parsedPartial.clipIds.filter((id: string) =>
        isPlayableClip(clips.clipById[id])
      ).length;
    } else if (!!parsedPartial?.parsed_content?.clipIds) {
      clipsIndexes[msgIndex] = currentIndex;
      currentIndex += parsedPartial.parsed_content.clipIds.filter(
        (id: string) => isPlayableClip(clips.clipById[id])
      ).length;
    }
  });

  useEffect(() => {
    // get message index and clip relative index for existing clips and queue
    if (
      queue.contextType === ContextType.Orpheus &&
      queue.contextId === chatUUID &&
      queue.activeQueue === 'context' &&
      cachedClipIndexes.current
    ) {
      const currentIndex = queue.contextQueueIndex;
      const messageIndex = Object.entries(cachedClipIndexes.current).findLast(
        ([_, clipIndex]) => {
          return Number(clipIndex) <= currentIndex;
        }
      )?.[0];
      if (!messageIndex) return;
      const clipRelativeIndex =
        currentIndex - (cachedClipIndexes.current[messageIndex] ?? 0);
      const newCurrentIndex =
        clipsIndexes[messageIndex as any] + clipRelativeIndex;
      if (newCurrentIndex !== queue.contextQueueIndex) {
        queue.setCurrentIndex(newCurrentIndex);
      }
      const newClips = messageClipIds.map((id) => clips.clipById[id]) as Clip[];
      queue.setClips(newClips);
    }
    cachedClipIndexes.current = clipsIndexes;
  }, [
    clipsIndexes,
    messageClipIds,
    chatUUID,
    queue.contextId,
    queue.contextType,
    queue.activeQueue,
    queue.contextQueueIndex,
  ]);

  return { messageClipIds, clipsIndexes };
};
