// @ts-ignore
import * as types from './types';
import { TransactionBuilder } from "./transactionBuilder";
// import { createLibp2p } from 'libp2p'
// import * as filters from '@libp2p/websockets/filters'
import { finalizeEvent, verifyEvent, setNostrWasm, VerifiedEvent, Event } from 'nostr-tools/wasm'
import { SimplePool } from 'nostr-tools/pool'
// import { gossipsub } from '@chainsafe/libp2p-gossipsub'
// import { noise } from '@chainsafe/libp2p-noise'
// import { yamux } from '@chainsafe/libp2p-yamux'
// import { mplex } from '@libp2p/mplex'
// import { identify } from "@libp2p/identify"
// import { dcutr } from "@libp2p/dcutr"
import { getPublicKey } from 'nostr-tools/pure';
import { initNostrWasm } from 'nostr-wasm'
// import { multiaddr } from '@multiformats/multiaddr'
import { useWebSocketImplementation } from 'nostr-tools/pool'
import WebSocket from 'ws'
import { Block } from 'ethers';

if (typeof global === "object") useWebSocketImplementation(WebSocket);


export class Peering extends TransactionBuilder {

    // p2p: any | undefined; 
    pool: SimplePool = new SimplePool();
    relays: string[];
    seeds: string[];
    rebroadcast: any | undefined;
    // callback: Function;

    constructor(_config: types.GlobalConfig) {
        super(_config);
        // if (!this.config.gossip) throw new Error("Gossip config not found");
        this.pool = new SimplePool();
        this.relays = this.config.gossip!.relays;
        this.seeds = this.config.gossip!.seeds;
        // this.callback = () => true;
    }

    postEvent = async (_sk: Uint8Array, _timestamp: number, ips: string) => Promise.any(this.pool.publish(this.relays, finalizeEvent({
        kind: 1,
        created_at: _timestamp,
        tags: [],
        content: ips
    }, _sk)))

    // postTransaction = async (_tx: types.Transaction) => {
    //     const hexString = (await this.contracts.state.getAddress()).slice(2).padStart(64, '0');
    //     const matches = hexString.match(/.{1,2}/g);
    //     const skUint8Array = matches ? new Uint8Array(matches.map(byte => parseInt(byte, 16))) : new Uint8Array();
    //     const _pk: string = getPublicKey(skUint8Array);

    //     if (this.p2p.services.pubsub.getSubscribers(_pk).length > 0) {
    //         await this.p2p.services.pubsub.publish(_pk, new TextEncoder().encode(JSON.stringify(_tx)))
    //     } else {
    //         setTimeout(async () => await this.postTransaction(_tx), 10_000);
    //     }
    // };
    initializePeering = async (callback?: Function): Promise<void> => {
        await this.initializeTransactionBuilder();
        const hexString = "6835ccbeddc1c1c91fed2116099592a309f98d0df34d8dc72e770df83cc3b065".padStart(64, '0');
        const matches = hexString.match(/.{1,2}/g);
        const skUint8Array = matches ? new Uint8Array(matches.map(byte => parseInt(byte, 16))) : new Uint8Array()
        let _pk = getPublicKey(skUint8Array);
        await this.fetchRelays();
        await initNostrWasm().then(setNostrWasm);
        const latestBlock = await this.config.provider.getBlock("latest");
        let ip: string
        if (this.config.ip == "") {
            let ips: string[] = []
            let ipServices = ["https://api.ipify.org", "https://icanhazip.com", "https://ifconfig.me/ip", "https://checkip.amazonaws.com/"]
            for (let i = 0; i < ipServices.length; i++) {
                let res = await fetch(ipServices[i])
                ips.push((await res.text()).trim())
            }
            let last = ips[0]
            for (let i = 0; i < ips.length; i++) {
                if (last === ips[i]) {
                    last = ips[i]
                } else {
                    console.log("Please set your public ip in the config file")
                    return
                }
            }
            ip = last
        }else {
            ip = this.config.ip as string
        }
        if (typeof global === 'object') {
            this.rebroadcast = setInterval(async () => {
                await this.postEvent(skUint8Array, latestBlock!.timestamp, ip)
            }, 60 * 60 * 1000);

            await this.postEvent(skUint8Array, latestBlock!.timestamp, ip);
        }

    }

    queryEvents = async (latestBlock: number) => {
        const hexString = "6835ccbeddc1c1c91fed2116099592a309f98d0df34d8dc72e770df83cc3b065".padStart(64, '0');
        const matches = hexString.match(/.{1,2}/g);
        const skUint8Array = matches ? new Uint8Array(matches.map(byte => parseInt(byte, 16))) : new Uint8Array()
        let _pk = getPublicKey(skUint8Array);
        let event = await this.pool.querySync(this.relays, {
            kinds: [1],
            authors: [_pk],
            since: latestBlock - (typeof global === 'object' ? 0 : 86400)

        })
    }
    fetchRelays = async (refresh: boolean = false): Promise<string[]> => {
        if (this.seeds.length == 0 || refresh) return this.relays;
        for (const seed of this.seeds) {
            const relaysFromSeed: string[] = (await (await fetch(seed)).json()) as string[];
            this.relays = this.relays.concat(relaysFromSeed);
        }
        return this.relays;
    }
}

/* eslint-disable no-console */