/* eslint-disable @typescript-eslint/no-unused-vars */

import { ChatResponseItem, Conversation, Message } from '@aichatkit/types'

export interface StorageAdapterCallbacks {
  /**
   * Callback to get conversation items from network
   * @param agentId The ID of the agent
   * @returns Promise with array of response items
   */
  getConversationItems?: (agentId: string) => Promise<ChatResponseItem[]>

  /**
   * Callback to clear conversation history on network
   * @param agentId The ID of the agent
   * @returns Promise that resolves when cleared
   */
  clearConversationHistory?: (agentId: string) => Promise<void>
}

export abstract class StorageAdapter {
  protected callbacks?: StorageAdapterCallbacks

  /**
   * Set network callbacks for syncing with backend
   * @param callbacks Network adapter callbacks
   */
  setNetworkCallbacks(callbacks: StorageAdapterCallbacks): void {
    this.callbacks = callbacks
  }

  /**
   * Saves a conversation to storage
   * @param conversation Conversation to save
   * @returns Promise that resolves when the operation is complete
   */
  abstract saveConversation(conversation: Conversation): Promise<void>

  /**
   * Retrieves a conversation from storage by ID
   * @param id ID of the conversation to retrieve
   * @returns Promise that resolves with the conversation or null if not found
   */
  abstract getConversation(id: string): Promise<Conversation | null>

  /**
   * Retrieves all conversations from storage
   * @returns Promise that resolves with an array of conversations
   */
  abstract getAllConversations(): Promise<Conversation[]>

  /**
   * Deletes a conversation from storage
   * @param id ID of the conversation to delete
   * @returns Promise that resolves with a boolean indicating success
   */
  abstract deleteConversation(id: string): Promise<boolean>

  /**
   * Adds a response item to a conversation
   * @param conversationId ID of the conversation
   * @param item Response item to add
   * @returns Promise that resolves with the updated conversation or null if not found
   */
  abstract addItem(
    conversationId: string,
    item: ChatResponseItem,
  ): Promise<Conversation | null>

  /**
   * Adds a message to a conversation (convenience method)
   * @param conversationId ID of the conversation
   * @param message Message to add
   * @returns Promise that resolves with the updated conversation or null if not found
   */
  async addMessage(
    conversationId: string,
    message: Message,
  ): Promise<Conversation | null> {
    const messageItem: ChatResponseItem = {
      id: message.id,
      type: 'message',
      content: message.content,
      role: message.role,
      timestamp: message.timestamp,
    } as any

    return this.addItem(conversationId, messageItem)
  }

  /**
   * Get conversation items - syncs with backend if callback available
   * @param conversationId ID of the conversation
   * @returns Promise with array of response items
   */
  abstract getConversationItems(
    conversationId: string,
  ): Promise<ChatResponseItem[]>

  /**
   * Get conversation history (messages only) - syncs with backend if callback available
   * @param conversationId ID of the conversation
   * @returns Promise with array of messages
   */
  async getConversationHistory(conversationId: string): Promise<Message[]> {
    const items = await this.getConversationItems(conversationId)

    // Filter and convert message items to message format
    return items
      .filter((item) => item.type === 'message')
      .map((item) => {
        const msgItem = item as any
        return {
          id: msgItem.id,
          content: msgItem.content,
          role: msgItem.role,
          timestamp: msgItem.timestamp,
        }
      })
  }

  /**
   * Clear conversation history - syncs with backend if callback available
   * @param conversationId ID of the conversation
   * @returns Promise that resolves when history is cleared
   */
  abstract clearConversationHistory(conversationId: string): Promise<void>

  /**
   * Store agent ID for a conversation
   * @param conversationId ID of the conversation
   * @param agentId ID of the agent
   * @returns Promise that resolves when stored
   */
  abstract setConversationAgent(
    conversationId: string,
    agentId: string,
  ): Promise<void>

  /**
   * Get agent ID for a conversation
   * @param conversationId ID of the conversation
   * @returns Promise with agent ID or null if not found
   */
  abstract getConversationAgent(conversationId: string): Promise<string | null>

  /**
   * Sync all conversations with backend to ensure consistency
   * @returns Promise that resolves when sync is complete
   */
  async syncAllConversationsWithBackend?(): Promise<void> {
    if (!this.callbacks?.getConversationItems) {
      return Promise.resolve()
    }

    try {
      const conversations = await this.getAllConversations()

      for (const conversation of conversations) {
        const agentId = await this.getConversationAgent(conversation.id)

        if (agentId) {
          try {
            const backendItems =
              await this.callbacks.getConversationItems(agentId)
            conversation.items = backendItems
            await this.saveConversation(conversation)
          } catch (error) {
            console.error(
              `Failed to sync conversation ${conversation.id}:`,
              error,
            )
          }
        }
      }
    } catch (error) {
      console.error('Failed to sync conversations with backend:', error)
    }

    return Promise.resolve()
  }

  /**
   * Optional method to initialize the adapter
   * @param config Optional configuration object
   */
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  async initialize(config?: Record<string, any>): Promise<void> {
    return Promise.resolve()
  }
}
