import type { UiMessage } from "@/data/dto/chat";
import { getChatRepository } from "@/data/repositories/chat_repository";
import { Logger, Result, todayString } from "@/utils";

import { localMessagesToUi, PAGE_SIZE } from "./chat-machine.helpers";

const log = new Logger("StoresChatChatHistorySync");

export type ReadAndSyncHistoryOutput = {
  /** Network-authoritative messages. Empty network history includes a UI greeting. */
  messages: UiMessage[];
  hasMore: boolean;
  newOffset: number;
  /** True when network history was written back to local storage. */
  localOverwritten: boolean;
  localCount: number;
  networkCount: number;
};

export type LocalHistorySnapshotOutput = {
  /** Local cached messages. Empty local history includes a UI greeting. */
  messages: UiMessage[];
  hasMore: boolean;
  newOffset: number;
  localCount: number;
};

export type NetworkHistorySyncOutput = ReadAndSyncHistoryOutput;

export function createGreetingMessage(): UiMessage {
  return {
    content:
      "You're here! Facebook is so restrictive, " +
      "there were things I couldn't say there. " +
      "Finally I can relax. How was your day out?",
    isFromAI: true,
    date: todayString(),
  };
}

export async function readLocalHistorySnapshot(): Promise<LocalHistorySnapshotOutput> {
  const chatRepo = getChatRepository();
  const greetingMessage = createGreetingMessage();

  const localResult = await chatRepo.getLocalMessages();
  const localMessages =
    Result.isOk(localResult) && localResult.data
      ? localMessagesToUi(localResult.data)
      : [];
  log.debug("[chat-machine] loadHistory LOCAL DONE", {
    count: localMessages.length,
  });

  const snapshotMessages =
    localMessages.length === 0 ? [greetingMessage] : localMessages;
  if (snapshotMessages[0] === greetingMessage) {
    log.debug("[chat-machine] loadHistory EMPTY -> prepend greeting (local)");
  }

  return {
    messages: snapshotMessages,
    hasMore: localMessages.length >= PAGE_SIZE,
    newOffset: snapshotMessages.length,
    localCount: localMessages.length,
  };
}

export async function syncNetworkHistory(
  localCount: number,
): Promise<NetworkHistorySyncOutput | null> {
  const chatRepo = getChatRepository();
  const greetingMessage = createGreetingMessage();

  const networkResult = await chatRepo.getHistory(PAGE_SIZE, 0);
  if (Result.isErr(networkResult)) {
    log.error("[chat-machine] loadHistory NETWORK FAILED", {
      error: networkResult.error,
    });
    return null;
  }

  const networkUi = localMessagesToUi(networkResult.data.messages);
  log.debug("[chat-machine] loadHistory NETWORK DONE", {
    count: networkUi.length,
  });
  void chatRepo.prefetchMediaForMessages(networkResult.data.messages);

  const saveResult = await chatRepo.saveMessagesToLocal(
    networkResult.data.messages,
  );
  const localOverwritten = Result.isOk(saveResult);
  log.debug("[chat-machine] loadHistory SAVE TO LOCAL DONE", {
    localOverwritten,
  });

  const finalMessages =
    networkUi.length === 0 ? [greetingMessage] : networkUi;
  if (finalMessages[0] === greetingMessage) {
    log.debug("[chat-machine] loadHistory EMPTY -> prepend greeting");
  }

  return {
    messages: finalMessages,
    hasMore: finalMessages.length >= PAGE_SIZE,
    newOffset: finalMessages.length,
    localOverwritten,
    localCount,
    networkCount: networkUi.length,
  };
}

/**
 * History sync flow:
 * 1. Read local history for fallback.
 * 2. Read network history as the authoritative source.
 * 3. Overwrite local history with network data.
 */
export async function readAndSyncHistory(): Promise<ReadAndSyncHistoryOutput> {
  const localSnapshot = await readLocalHistorySnapshot();
  const networkSnapshot = await syncNetworkHistory(localSnapshot.localCount);
  if (networkSnapshot) return networkSnapshot;

  return {
    messages: localSnapshot.messages,
    hasMore: localSnapshot.hasMore,
    newOffset: localSnapshot.newOffset,
    localOverwritten: false,
    localCount: localSnapshot.localCount,
    networkCount: 0,
  };
}
