import { fromPromise } from "xstate";

import { getChatRepository } from "@/data/repositories/chat_repository";
import { resolveChatCacheOwnerKey } from "@/data/repositories/chat_cache_identity";
import { Logger } from "@/utils/logger";
import { Result } from "@/utils/result";

import { readAndSyncHistory } from "../../chat-history-sync";
import {
  type UnlockMessageRequest,
  type UnlockMessageOutput,
} from "../../helper/unlock";

const log = new Logger("StoresChatChatUnlockFlow");

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

export interface UnlockHistoryOutput {
  unlocked: boolean;
  reason: string;
  shortfallCredits: number;
  messages: UiMessage[];
}

export const unlockHistoryActor = fromPromise<UnlockHistoryOutput>(async () => {
  const chatRepo = getChatRepository();
  const unlockResult = await chatRepo.unlockHistory();
  if (Result.isErr(unlockResult)) {
    log.error("[chat-machine] unlockHistoryActor failed", {
      error: unlockResult.error,
    });
    throw unlockResult.error;
  }

  const history = await readAndSyncHistory();
  return {
    unlocked: unlockResult.data.unlocked,
    reason: unlockResult.data.reason,
    shortfallCredits: unlockResult.data.shortfallCredits,
    messages: history.messages,
  };
});

export const unlockMessageActor = fromPromise<
  UnlockMessageOutput,
  UnlockMessageRequest
>(async ({ input }) => {
  const chatRepo = getChatRepository();
  const cacheIdentityResult = await resolveChatCacheOwnerKey();
  const unlockResult = await chatRepo.unlockPrivateMessage({
    ...(input.messageId ? { messageId: input.messageId } : {}),
    ...(input.lockType ? { lockType: input.lockType } : {}),
    ...(input.clientLockId ? { clientLockId: input.clientLockId } : {}),
  });
  if (Result.isErr(unlockResult)) {
    log.error("[chat-machine] unlockMessageActor failed", {
      messageId: input.messageId,
      clientLockId: input.clientLockId,
      error: unlockResult.error,
    });
    throw unlockResult.error;
  }

  if (
    unlockResult.data.unlocked &&
    input.messageId &&
    !input.clientLockId &&
    Result.isOk(cacheIdentityResult)
  ) {
    const markResult = await chatRepo.markPrivateMessageUnlockedInLocal(
      input.messageId,
      {
        content: unlockResult.data.content,
        audioUrl: unlockResult.data.audioUrl,
        ...(unlockResult.data.image.url
          ? { image: unlockResult.data.image }
          : {}),
        lockDetail: { locked: false, reason: null },
      },
      cacheIdentityResult.data,
    );
    if (Result.isErr(markResult)) {
      log.warn("[chat-machine] mark unlocked local message failed", {
        messageId: input.messageId,
        error: markResult.error,
      });
    }
  }

  return {
    displayMessageId: input.displayMessageId,
    request: input,
    response: unlockResult.data,
  };
});
