import { inviteKind, ndk } from '@/ndk';
import { getActiveCCNNpub, getCCNName } from '@/utils/getCCNList';
import { randomBytes } from '@noble/ciphers/webcrypto';
import { NDKEvent } from '@nostr-dev-kit/ndk';
import { sha512Hash } from '@utils/sha512';
import { LitElement, css, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { when } from 'lit/directives/when.js';

import { generateInvite } from '@/utils/invite';
import '@components/CCNInvitation';
import '@components/General/Button';
import '@components/MarkdownContent';
import { bytesToHex } from '@noble/ciphers/utils';
import type { NPub } from '@nostr/tools/nip19';

// generate invite code
// broadcast invite event to CCN { "invite": sha512Hash(inviteCode) }
// invitee receives invite code
// invitee generates nsec
// invitee generates DM with their invite code to the CCN
// upon receipt of message where sha512Hash(message) matches a valid invite code, the CCN (inviter only) will broadcast an accept invite event to all peers
// CCN (inviter only) will DM CCN seed to invitee
// CCN invalidates invite code

@customElement('arx-invite-code-generator')
export class InviteCodeGenerator extends LitElement {
  static override styles = css`
    :host {
      display: block;
      padding: 32px;
      max-width: 600px;
      margin: 0 auto;
    }
  `;

  @state() inviteCode = '';
  @state() ccnNpub?: NPub;
  @state() ccnName = '';
  @state() isGenerating = false;
  @state() generatedInvite = '';

  override async connectedCallback() {
    super.connectedCallback();
    const npub = getActiveCCNNpub();
    if (!npub) throw new Error('No CCN selected');
    const ccnName = await getCCNName(npub);
    if (!ccnName) throw new Error('CCN name not found');
    this.ccnNpub = npub;
    this.ccnName = ccnName;
  }

  private async generateAndBroadcastInvite() {
    if (this.inviteCode) return alert('Invite already generated');
    if (this.isGenerating) return;
    this.isGenerating = true;
    try {
      this.inviteCode = bytesToHex(randomBytes(32));
      const event = new NDKEvent(ndk);
      event.kind = inviteKind;
      event.content = '';
      event.tags = [['i', sha512Hash(this.inviteCode)]];
      await event.sign();
      await event.publish();
      this.generatedInvite = generateInvite(this.ccnNpub!, this.inviteCode);
    } catch (error) {
      console.error('Failed to generate and broadcast invite:', error);
    } finally {
      this.isGenerating = false;
    }
  }

  private async copyToClipboard() {
    if (!this.generatedInvite) return;
    await navigator.clipboard.writeText(this.generatedInvite);
  }

  override render() {
    return html`
      <arx-button
        @click=${this.generateAndBroadcastInvite}
        ?disabled=${this.isGenerating}
        variant="accent"
        label=${this.isGenerating ? 'Generating...' : 'Generate Invite'}
      ></arx-button>
      ${when(
        this.inviteCode,
        () => html`
          <arx-button
            @click=${this.copyToClipboard}
            variant="secondary"
            label="Copy Invite"
          ></arx-button>
          <arx-ccn-invitation
            ccnNpub=${ifDefined(this.ccnNpub)}
            ccnName=${this.ccnName}
            invite=${this.generatedInvite}
          ></arx-ccn-invitation>
        `,
      )}
    `;
  }
}
