"use client";

import type { ChatLockDetailData } from "@/data/schemas/chat";
import { ChatMessage } from "@/data/dto/chat";
import { LocalChatStorage, LocalMessage } from "@/data/storage/chat";
import { Result } from "@/utils";

export class ChatLocalMessageStore {
  constructor(private readonly localStorage: LocalChatStorage) {}

  async markMessageUnlocked(
    messageId: string,
    lockDetail?: ChatLockDetailData,
  ): Promise<Result<void>> {
    return Result.wrap(async () => {
      const localResult = await this.getMessages();
      if (Result.isErr(localResult)) {
        throw localResult.error;
      }

      let changed = false;
      const updatedMessages = localResult.data.map((message) => {
        if (!shouldMarkMessageUnlocked(message, messageId)) return message;
        changed = true;
        return ChatMessage.from({
          ...message.toJson(),
          lockDetail: lockDetail ?? {
            ...message.lockDetail,
            locked: false,
            showContent: true,
            showUpgrade: false,
            reason: null,
            hint: null,
            detail: null,
          },
        });
      });

      if (!changed) return;

      const saveResult = await this.saveMessages(updatedMessages);
      if (Result.isErr(saveResult)) {
        throw saveResult.error;
      }
    });
  }

  async saveMessage(message: ChatMessage): Promise<Result<void>> {
    return this.localStorage.saveMessage(this._chatToLocal(message));
  }

  async saveMessages(
    messages: readonly ChatMessage[],
  ): Promise<Result<void>> {
    const cleared = await this.localStorage.clearAll();
    if (!cleared.success) {
      return Result.err(cleared.error);
    }
    return this.localStorage.saveMessages(
      messages.map((message) => this._chatToLocal(message)),
    );
  }

  async getMessages(): Promise<Result<ChatMessage[]>> {
    const result = await this.localStorage.getAllMessages();
    if (!result.success) {
      return Result.err(result.error);
    }
    return Result.ok(result.data.map((message) => this._localToChat(message)));
  }

  async clearMessages(): Promise<Result<void>> {
    return this.localStorage.clearAll();
  }

  async getMessageCount(): Promise<Result<number>> {
    return this.localStorage.getMessageCount();
  }

  private _chatToLocal(message: ChatMessage): LocalMessage {
    return LocalMessage.from({
      id: message.id,
      role: message.role,
      type: message.type,
      content: message.content,
      createdAt: message.createdAt,
      audioUrl: message.audioUrl,
      image: message.image,
      lockDetail: message.lockDetail,
      sessionId: "",
    });
  }

  private _localToChat(local: LocalMessage): ChatMessage {
    return ChatMessage.from({
      id: local.id,
      role: local.role,
      type: local.type,
      content: local.content,
      createdAt: local.createdAt,
      audioUrl: local.audioUrl,
      image: local.image,
      lockDetail: local.lockDetail,
    });
  }
}

function shouldMarkMessageUnlocked(
  message: ChatMessage,
  messageId: string,
): boolean {
  if (message.id !== messageId) return false;
  if (message.role !== "assistant") return false;
  if (message.lockDetail.locked !== true) return false;
  return (
    Boolean(message.image.url) ||
    message.lockDetail.reason === "private_message" ||
    message.lockDetail.reason === "voice_message"
  );
}
