// initialize required packages
const fs = require('fs');
const ini = require('ini');
const nostr = require('nostr-tools');
const os = require('os');
const path = require('path');
const wspf = require('websocket-polyfill');
const WebSocket = require('ws');
const xmpp = require('simple-xmpp');


// nostr things
let {
  bech32,
  bech32m
} = require('bech32');

let letsCID;
let signedEvent;


// config setup for home folders
// Determine the platform-specific config path
function getConfigPath() {
    const platform = os.platform();
    if (platform === 'win32') {
        // Windows
        return path.join(process.env.APPDATA, 'nostrsms', 'config.ini');
    } else if (platform === 'darwin') {
        // macOS
        return path.join(os.homedir(), 'Library', 'Application Support', 'nostrsms', 'config.ini');
    } else {
        // Linux and other Unix-like systems
        return path.join(os.homedir(), '.config', 'nostrsms', 'config.ini');
    }
}

// prepare config for parsing
const configPath = getConfigPath();
if (fs.existsSync(configPath)) {
  console.log(`Found config at ${configPath}`);
  const config = ini.parse(fs.readFileSync(configPath, 'utf-8'));
  // get users nostr private hex
  let sk = config.nostr.pkhex;
  // calculate pubkey from private
  let pk = nostr.getPublicKey(sk);

  // only allow users from config.ini -> [authorized_users] -> users
  const authorizedUsers = config.authorized_users.users
  ? config.authorized_users.users.split(',').map(user => user.trim())
  : [];

  // We've got a connection to XMPP!
  xmpp.on('online', function (data, to) {
    console.log('Connected with JID: ' + config.xmpp.jid);
    console.log('Pubkey: ' + pk);
  });

  // We've got an XMPP message!
  xmpp.on('chat', function (from, message) {
    // setup debugging based on config.ini
    function debug() {
      if (config.debug === '1') {
        console.log('[DEBUG]');
        console.log(message);
        console.log(from);
      };
    }
    // deny users not in config.ini
    if (!authorizedUsers.includes(from)) {
      xmpp.send(from, 'Not authorized');
      debug();
      return; // Exit the function early
    }

    // get the latest documentation for nostrsms
    if (message === '!help') {
      xmpp.send(from, 'https://wiki.vanderwarker.family/doku.php?id=code:nostrsms:commands');
      debug();

    // get latest 10 posts from global
    } else if (message === "!g") {
      xmpp.send(from, `Here are the latest 10 posts from global on ${config.relays.read}`);
      async function getGlobalEvents() {		
        // use read relays in config.ini
        const relay = nostr.relayInit(config.relays.read, WebSocket);
        // connect to read relay
        relay.on('connect', () => {		
          console.log(`connected to ${relay.url}`);		
        });		
        relay.on('error', () => {		
          console.log(`failed to connect to ${relay.url}`);		
        });		

        await relay.connect();		

        // create subscription to get events
        let sub = relay.sub([{		
          kinds: [1],
          limit: 10		
        }, ])		
        // we've go an event! time to parse!
        sub.on('event', event => {		
          console.log('got event:', event);		
    		
          // Check if the event is already an object
          const globalEvents = typeof event === 'string' ? JSON.parse(event) : event;		
    		  // if globalEvents.* is set, set to const for later use
          if (globalEvents && globalEvents.content && globalEvents.pubkey && globalEvents.created_at) {		
            const content = globalEvents.content;		
            const author = globalEvents.pubkey;		
            const createdAt = globalEvents.created_at;		
    		
            // WIP move to debug
            console.log('Content:', content);		
            console.log('Author:', author);		
            console.log('Created At:', createdAt);		
    		
            // send the latest posts to the user whom requested them
            xmpp.send(from, `\"${content}\", - ${author} @ ${createdAt}`);
            relay.close();		
          } else {		
            console.error('Invalid event structure or missing required properties.');		
          }		
        });		
      }

      // let's run the above code to get our events and send them on XMPP/SMS! :)
      getGlobalEvents().catch((error) => {		
        console.error(error);		
      });

    // Well they didn't use a command, so let's get to the NOSTR STUFF!!1!
    } else {
      async function newPost() {
        // get relays from config.ini
        const relay = nostr.relayInit(config.relays.write, WebSocket);
        // look at that, already on the nostr
        relay.on('connect', () => {
          console.log(`connected to ${relay.url}`);
        });
        // dang...failed connection! Try again sooon, or try one of the thousands of other relays ;)
        relay.on('error', () => {
          console.log(`failed to connect to ${relay.url}`);
        });

        // wait for the above to give us the go ahead
        await relay.connect();

        // let's construct our "note"!
        let event = {
          // https://git.vanderwarker.family/nostr/nips/src/branch/master/01.md
          kind: 1,
          // get users public key hex
          pubkey: pk,
          // create this instant! (timestamp)
          created_at: Math.floor(Date.now() / 1000),
          // add client tag for UIs to optionally display
          tags: [['client','NostrSMS','31990:9be1b8315248eeb20f9d9ab2717d1750e4f27489eab1fa531d679dadd34c2f8d:1726937516']],
          // set the nostr content to the incoming xmpp message
          content: message,
        };
        // sign nostr event
        const signedEvent = nostr.finishEvent(event, sk);
        // get nostr event it
        letsCID = signedEvent.id;
        showSID(letsCID, pk);
        // publish!
        await relay.publish(signedEvent);
        // done here. we can disconnect! (from nostr relay)
        relay.close();
      }
      // catch errors
      newPost().catch((error) => {
        console.error(error);
      });

      // get's id, pubkey, kind, from signed event, and relay from config.ini and create
      // a nip-19 encoded entity to send back to the user
      // this can be pasted into most nostr clients for immediate fetching/viewing
      async function showSID(letsCID, pk) {
        console.log(letsCID);
        console.log(pk);
        const event = {
          id: letsCID,
          relays: [config.relays.write],
          author: pk,
          kind: 1,
        };
        const encodedNEvent = nostr.nip19.neventEncode(event);
        xmpp.send(from, "nostr:" + encodedNEvent);
        console.log(encodedNEvent)
        debug();
      }
    }
  });
  // xmpp seems to have an error, so we show it in the console
  xmpp.on('error', function (err) {
    console.error(err);
  });
  // set xmpp presence to nostrsms url (free advertisement! :P)
  xmpp.setPresence('chat', 'https://nostrsms.com');
  // connect to xmpp server using info from config.ini
  xmpp.connect({
    jid: config.xmpp.jid,
    password: config.xmpp.password,
    host: config.xmpp.host,
    port: 5222
  });
 // catch ctrl+c
 // TODO: add confirmation ??
  process.on('SIGINT', function () {
    console.log("SigInt receieved. Shutdown inevitable!")
    process.exit();
  });

// error out and show install instructions if config.ini isn't found.
} else {
  console.log("=_-_+_-_=_-_+_-_=_-_+_-_=_-_+_-_=_-_+_-_=");
  console.error("Config file not found at ${configPath}");
  console.log("=_-_+_-_=_-_+_-_=_-_+_-_=_-_+_-_=_-_+_-_=");
  console.log("");
  console.log("Please create a config.ini");
  console.log("See https://wiki.vanderwarker.family/doku.php?id=code:nostrsms:install");
  console.log("and choose your preferred install method.");
  process.exit(1);
}