import type { IDAgent } from '../agent/index.js';

import { createLibp2p } from 'libp2p';
import { circuitRelayTransport } from 'libp2p/circuit-relay';
import { gossipsub } from '@chainsafe/libp2p-gossipsub';
import { identifyService } from 'libp2p/identify';

import { kadDHT } from '@libp2p/kad-dht';
import { mplex } from '@libp2p/mplex';
import { noise } from '@chainsafe/libp2p-noise';
import { PubSub } from 'pubsub-js';
import { webRTCStar } from '@libp2p/webrtc-star';
import { yamux } from '@chainsafe/libp2p-yamux';

export class Queue {
  private agent: IDAgent;
  private connectedDid: string;
  private _star: any;

  constructor(options: { agent: IDAgent, connectedDid: string }) {
    this.agent = options.agent;
    this.connectedDid = options.connectedDid;

    this._star = webRTCStar();
  }

  async createPeer(): Promise<any>  {

    return await createLibp2p({
      addresses: {
        listen: [
          '/dns4/star.abaxx.id/tcp/443/wss/p2p-webrtc-star/',
        ],
      },
      transports: [
        this._star.transport,
        circuitRelayTransport({
          discoverRelays: 1,
        }),
      ],
      connectionEncryption: [
        //@ts-ignore
        new noise(), // elliptic curve Diffie-Hellman key exchange using Curve e25519
      ],
      streamMuxers: [
        //@ts-ignore
        new yamux(), new mplex(),
      ],
      peerDiscovery: [
        this._star.discovery,
      ],
      services: {
        //@ts-ignore
        pubsub: new gossipsub({
          allowPublishToZeroPeers : true,
          enabled                 : true,
          emitSelf                : true,
        }),
        identify : identifyService(),
        dht      : kadDHT({
          clientMode: true,
        }),
      },
    });

  }

  async send(node, topic, message) {
    node?.services?.pubsub?.publish(topic, new TextEncoder().encode(message)).catch((err) => {
      return { ok: false, error: err.message, timestsamp: new Date().getTime() };
    });
    return { ok: true, timestsamp: new Date().getTime() };
  }

  async publish(topic, message, relayers = []) {
    const response = await fetch(`${relayers[0]}/publish`, {
      method  : 'POST',
      mode    : 'cors',
      cache   : 'no-cache',
      headers : {
        'Accept'       : '*/*',
        'Content-Type' : 'application/json',
      },
      body: JSON.stringify({
        topic,
        message,
      }),
    });

    PubSub.publish(topic, message);
    return await response.text();
  }

  async subscribe(topic, cb) {
    const relaySubscriber = (msg, data) => {
      if (msg === topic) {
        cb(data);
      }
    };
    const subscriber = PubSub.subscribe(topic, relaySubscriber);
    return subscriber;
  }

  async unsubscribe(topic) {
    PubSub.unsubscribe(topic);
  }
}