// Copyright(c) 2025 3NSoft Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

mod deno_rt;

use ipc_duplex::{connect_and_run_ipc_channel, IpcClientEvent, SignalToSend};
use std::{env, process::exit, sync::{atomic::AtomicBool, Arc}};
use tokio::{self, sync::mpsc::{self, Receiver, Sender}};

use crate::deno_rt::make_and_run_deno_with_main_js;

macro_rules! some_or_exit {
  ($code:expr, $err_msg:literal) => {
    match $code {
      Some(v) => v,
      None => {
        eprintln!($err_msg);
        exit(-1);
      }
    }
  };
}

#[tokio::main]
async fn main() {
  let mut args = env::args();
  // skip path of this binary
  args.next();
  let ipc_connection_path = some_or_exit!(args.next(), " ❌ no argument given for ipc name/path to connect at");
  let main_js_path = some_or_exit!(args.next(), "\n ❌ no argument given for main js script path\n");

  let (tx, rx_to_ipc) = mpsc::channel::<SignalToSend>(1);
  let (tx_from_ipc, rx) = mpsc::channel::<IpcClientEvent>(1);
  let in_progress = Arc::new(AtomicBool::new(true));

  let deno_thread = tokio::runtime::Handle::current().spawn_blocking(move || {
    run_deno_thread(&main_js_path, tx, rx)
  });

  let _ = tokio::spawn(
    connect_and_run_ipc_channel(ipc_connection_path, tx_from_ipc, rx_to_ipc, in_progress)
  ).await;

  let _ = deno_thread.await;
}

fn run_deno_thread(main_js_path: &String, tx: Sender<SignalToSend>, rx: Receiver<IpcClientEvent>) {

  println!("Spawning thread for Deno");

  let rt = tokio::runtime::Builder::new_current_thread()
    .enable_all()
    .build()
    .expect("Fail to create tokio runtime for deno execution");
  if let Err(error) = rt.block_on(
    make_and_run_deno_with_main_js(main_js_path, tx, rx)
  ) {
    eprintln!("\n ❌ in running deno core:\n{}", error);
  }
}