import { fromCallback, fromPromise } from "xstate";

import { getChatRepository } from "@/data/repositories/chat_repository";
import { Logger, Result } from "@/utils";

import {
  readLocalHistorySnapshot,
  syncNetworkHistory,
} from "./chat-history-sync";
import {
  PAGE_SIZE,
  localMessagesToUi,
} from "./chat-machine.helpers";
import type { ChatEvent } from "./chat-events";

const log = new Logger("StoresChatChatHistoryFlow");

type UiMessage = import("@/data/dto/chat").UiMessage;

export const loadHistoryActor = fromCallback<ChatEvent>(({ sendBack }) => {
  let cancelled = false;

  void (async () => {
    const localSnapshot = await readLocalHistorySnapshot();
    if (cancelled) return;
    sendBack({
      type: "ChatLocalHistoryLoaded",
      output: localSnapshot,
    });

    const networkSnapshot = await syncNetworkHistory(
      localSnapshot.localCount,
    );
    if (cancelled || !networkSnapshot) return;
    sendBack({
      type: "ChatNetworkHistoryLoaded",
      output: networkSnapshot,
    });
  })().catch((error: unknown) => {
    if (cancelled) return;
    log.error("[chat-machine] loadHistoryActor failed", { error });
    sendBack({ type: "ChatHistoryLoadFailed", error });
  });

  return () => {
    cancelled = true;
  };
});

export const loadMoreHistoryActor = fromPromise<
  { messages: UiMessage[]; hasMore: boolean; newOffset: number },
  { offset: number }
>(async ({ input }) => {
  const chatRepo = getChatRepository();
  const result = await chatRepo.getHistory(PAGE_SIZE, input.offset);
  if (Result.isErr(result)) {
    log.error("[chat-machine] loadMoreHistoryActor failed", {
      error: result.error,
    });
    throw result.error;
  }
  const page = localMessagesToUi(result.data.messages);
  void chatRepo.prefetchMediaForMessages(result.data.messages);
  return {
    messages: page,
    hasMore: page.length >= PAGE_SIZE,
    newOffset: input.offset + page.length,
  };
});
