import { IDBPDatabase, openDB } from 'idb'
import { Event } from 'nostr-tools'
import { CachedEvent } from '../../types'
import { SchemaV2 } from './schema'

class LocalCache {
  // Static property to hold the single instance of LocalCache
  private static instance: LocalCache | null = null
  private db!: IDBPDatabase<SchemaV2>

  // Private constructor to prevent direct instantiation
  private constructor() {}

  // Method to initialize the database
  private async init() {
    this.db = await openDB<SchemaV2>('sigit-cache', 2, {
      upgrade(db, oldVersion) {
        if (oldVersion < 1) {
          db.createObjectStore('userMetadata', { keyPath: 'event.pubkey' })
        }

        if (oldVersion < 2) {
          const v6 = db as unknown as IDBPDatabase<SchemaV2>

          v6.createObjectStore('userRelayListMetadata', {
            keyPath: 'event.pubkey'
          })
        }
      }
    })
  }

  // Static method to get the single instance of LocalCache
  public static async getInstance(): Promise<LocalCache> {
    // If the instance doesn't exist, create it
    if (!LocalCache.instance) {
      LocalCache.instance = new LocalCache()
      await LocalCache.instance.init()
    }
    // Return the single instance of LocalCache
    return LocalCache.instance
  }

  // Method to add user metadata
  public async addUserMetadata(event: Event) {
    await this.db.put('userMetadata', { event, cachedAt: Date.now() })
  }

  // Method to get user metadata by key
  public async getUserMetadata(key: string): Promise<CachedEvent | null> {
    const data = await this.db.get('userMetadata', key)
    return data || null
  }

  // Method to delete user metadata by key
  public async deleteUserMetadata(key: string) {
    await this.db.delete('userMetadata', key)
  }

  public async addUserRelayListMetadata(event: Event) {
    await this.db.put('userRelayListMetadata', { event, cachedAt: Date.now() })
  }

  public async getUserRelayListMetadata(
    key: string
  ): Promise<CachedEvent | null> {
    const data = await this.db.get('userRelayListMetadata', key)
    return data || null
  }

  public async deleteUserRelayListMetadata(key: string) {
    await this.db.delete('userRelayListMetadata', key)
  }

  // Method to clear cache data
  public async clearCacheData() {
    // Clear the 'userMetadata' store in the IndexedDB database
    await this.db.clear('userMetadata')

    // Reload the current page to ensure any cached data is reset
    window.location.reload()
  }
}

// Export the single instance of LocalCache
export const localCache = await LocalCache.getInstance()
