import { Event, UnsignedEvent, EventTemplate, NostrEvent } from 'nostr-tools'
import { SignedEvent } from '../../types'
import { LoginMethodStrategy } from './loginMethodStrategy'
import { WindowNostr } from 'nostr-tools/nip07'

/**
 * Login Method Strategy when using nostr-login package.
 *
 * This class extends {@link LoginMethodStrategy base strategy} and implements all login method operations
 * @see {@link LoginMethodStrategy}
 */
export class NostrLoginStrategy extends LoginMethodStrategy {
  private nostr: WindowNostr

  constructor() {
    super()
    if (!window.nostr) {
      throw new Error(
        `window.nostr object not present. Make sure you have an nostr extension installed/working properly.`
      )
    }

    this.nostr = window.nostr as WindowNostr
  }

  async nip04Encrypt(receiver: string, content: string): Promise<string> {
    if (!this.nostr.nip04) {
      throw new Error(
        `Your nostr extension does not support nip04 encryption & decryption`
      )
    }

    const encrypted = await this.nostr.nip04.encrypt(receiver, content)
    return encrypted
  }

  async nip04Decrypt(sender: string, content: string): Promise<string> {
    if (!this.nostr.nip04) {
      throw new Error(
        `Your nostr extension does not support nip04 encryption & decryption`
      )
    }

    const decrypted = await this.nostr.nip04.decrypt(sender, content)
    return decrypted
  }

  async nip44Encrypt(receiver: string, content: string): Promise<string> {
    if (!this.nostr.nip44) {
      throw new Error(
        `Your nostr extension does not support nip44 encryption & decryption`
      )
    }

    // Encrypt the content using NIP-44 provided by the nostr extension.
    const encrypted = await this.nostr.nip44.encrypt(receiver, content)
    return encrypted as string
  }

  async nip44Decrypt(sender: string, content: string): Promise<string> {
    if (!this.nostr.nip44) {
      throw new Error(
        `Your nostr extension does not support nip44 encryption & decryption`
      )
    }

    // Decrypt the content using NIP-44 provided by the nostr extension.
    const decrypted = await this.nostr.nip44.decrypt(sender, content)
    return decrypted as string
  }

  async signEvent(event: UnsignedEvent | EventTemplate): Promise<SignedEvent> {
    return (await this.nostr
      .signEvent(event as NostrEvent)
      .catch((err: unknown) => {
        console.log('Error while signing event: ', err)

        throw err
      })) as Event
  }
}
