const WebSocket = require('ws');
const crypto = require('crypto');
const elliptic = require('elliptic');
const Buffer = require('safe-buffer').Buffer
const schnorr = require('bip-schnorr');
const settings = require('./settings.json');
// Use elliptic for ECDSA signing
const EC = elliptic.ec;
const ecdsa = new EC('secp256k1');

// Your Nostr private key (replace with your own)
const privateKeyHex = settings.secretKey; // Use your actual private key here

// Ensure private key is a valid 32-byte hex string
if (!/^([0-9a-fA-F]{64})$/.test(privateKeyHex)) {
  console.error('Invalid private key format. Ensure it is 64 hexadecimal characters.');
  process.exit(1);
}

const publicKeyHex = generatePublicKey(privateKeyHex);

// Connect to Binance WebSocket
const ws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@ticker');

// Handle WebSocket connection and data
ws.on('open', function open() {
  console.log('Connected to Binance WebSocket');
});

ws.on('message', function incoming(message) {
  const data = JSON.parse(message);

  // Extract relevant data
  const symbol = data.s;
  const lastPrice = parseFloat(data.c);
  const weightedAvgPrice = parseFloat(data.w);
  const highPrice = parseFloat(data.h);
  const lowPrice = parseFloat(data.l);

  // Create Nostr event
  const timestamp = Math.floor(Date.now() / 1000);
  const eventContent = JSON.stringify({
    symbol,
    last_price: lastPrice,
    weighted_avg_price: weightedAvgPrice,
    high_price: highPrice,
    low_price: lowPrice
  });

  const event = {
    id: '',
    pubkey: publicKeyHex,  // 32-byte public key
    created_at: timestamp,
    kind: 31892,  // Note (you can change this based on your event type)
    tags: [['d','BTCUSD'],['n', 'BTC','USD'],['value', 'lastPrice']],  // Optional tag (you can customize this)
    content: eventContent,
    sig: ''  // Initialize sig here, it will be added after content
  };

  // Compute event ID (sha256 of serialized event)
  const serializedEvent = serializeEvent(publicKeyHex, timestamp, event.kind, event.tags, eventContent);
  const eventId = crypto.createHash('sha256').update(serializedEvent).digest('hex');
  event.id = eventId;

  // Sign the event using elliptic library
  event.sig = signEvent(privateKeyHex, serializedEvent, event.id);

  // Print the Nostr event with signature under content
  console.log('Nostr Event:', JSON.stringify(event, null, 2));

  // Optionally, broadcast the event to a Nostr relay (example)
  sendToRelay(event);
});

// Function to generate compressed public key from private key using elliptic
function generatePublicKey(privateKeyHex) {
  const privateKey = Buffer.from(privateKeyHex, 'hex');

  if (privateKey.length !== 32) {
    console.error('Private key must be 32 bytes.');
    process.exit(1);
  }

  const key = ecdsa.keyFromPrivate(privateKey);
  const publicKey = key.getPublic(true, 'hex');  // Compressed format

  return publicKey.slice(2); // Remove the '0x' prefix to get 32 bytes
}

// Function to serialize the event according to NIP-01
function serializeEvent(pubkey, createdAt, kind, tags, content) {
  const eventData = [
    0,  // Prefix for NIP-01 event serialization
    pubkey,
    createdAt,
    kind,
    tags,
    content
  ];

  // Serialize the event to JSON string
  let eventJson = JSON.stringify(eventData, (key, value) => {
    // Escape content field (you can also add custom escaping here if necessary)
    if (key === 'content') {
      value = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
    }
    return value;
  });

  return eventJson;
}

// Function to sign the event with the private key using elliptic
function signEvent(privateKeyHex, serializedEvent, eventID) {
  const message = Buffer.from(eventID, 'hex');
  const signature = schnorr.sign(privateKeyHex, message);
  return signature.toString('hex');
}

// Function to send the event to a Nostr relay
function sendToRelay(event) {
  // Example relay URL (replace with the actual Nostr relay URL)
  const relayUrl = settings.relayUri;  // Replace with your relay URL

  // Create a WebSocket connection to the relay
  const relayWs = new WebSocket(relayUrl);

  relayWs.on('open', () => {
    // Once the connection is open, send the event
    const eventMessage = ['EVENT', event];  // Relay expects an array with 'EVENT' and event data
    relayWs.send(JSON.stringify(eventMessage));
    console.log('Event sent to relay:', JSON.stringify(event, null, 2));
  });

  relayWs.on('error', (err) => {
    console.error('Error sending event to relay:', err);
  });

  relayWs.on('close', () => {
    console.log('Connection to relay closed');
  });
}