import { inviteResponseKind, ndk } from '@/ndk';
import { bytesToHex } from '@noble/hashes/utils';
import { NDKEvent, NDKKind, NDKPrivateKeySigner, type NDKTag, NDKUser } from '@nostr-dev-kit/ndk';
import type { NPub } from '@nostr/tools/nip19';
import * as nostrTools from '@nostr/tools/pure';
import { base64 } from '@scure/base';
import { arrayToUnique } from './arrayToUnique';
export async function generateDM(npub: NPub, content: string, additionalTags: NDKTag[] = []) {
  if (!ndk.signer) {
    throw new Error('NDK signer not initialized');
  }

  const recipient = new NDKUser({
    npub,
  });

  const randomPrivateKey = nostrTools.generateSecretKey();
  const randomSigner = new NDKPrivateKeySigner(randomPrivateKey);

  const dmEvent = new NDKEvent(ndk);
  dmEvent.kind = NDKKind.PrivateDirectMessage;
  dmEvent.content = content;
  dmEvent.tags.push(['p', recipient.pubkey], ...additionalTags);
  await dmEvent.sign(ndk.signer);

  const sealEvent = new NDKEvent(ndk);
  sealEvent.kind = NDKKind.GiftWrapSeal;
  sealEvent.content = await randomSigner.encrypt(recipient, JSON.stringify(dmEvent), 'nip44');
  await sealEvent.sign(randomSigner);

  const giftWrapEvent = new NDKEvent(ndk);
  giftWrapEvent.kind = NDKKind.GiftWrap;
  giftWrapEvent.tags.push(['p', recipient.pubkey], ...additionalTags);
  giftWrapEvent.content = await randomSigner.encrypt(recipient, JSON.stringify(sealEvent), 'nip44');
  await giftWrapEvent.sign(randomSigner);

  return giftWrapEvent;
}

export async function decryptInviteResponseDM(event: NDKEvent): Promise<{
  privateKey: string;
  existingMembers: string[];
  ccnName: string;
}> {
  if (event.kind !== NDKKind.GiftWrap) {
    throw new Error('Event is not a gift wrap');
  }

  const seal = JSON.parse(await ndk.signer?.decrypt(event.author, event.content, 'nip44')!);
  if (seal.kind !== NDKKind.GiftWrapSeal) {
    throw new Error('Seal is not a gift wrap seal');
  }

  const inviteResponse = JSON.parse(await ndk.signer?.decrypt(event.author, seal.content, 'nip44')!);
  if (inviteResponse.kind !== inviteResponseKind) {
    throw new Error('Invite response is not of correct type');
  }

  const privateKey = base64.decode(inviteResponse.content);
  return {
    privateKey: bytesToHex(privateKey),
    existingMembers: arrayToUnique(inviteResponse.tags.filter((tag) => tag[0] === 'p').map((tag) => tag[1])),
    ccnName: inviteResponse.tags.find((tag) => tag[0] === 'name')?.[1],
  };
}
