use std::cell::RefCell;
use std::fs;
use std::path::Path;

use async_process::{Child, Command, Stdio};
use nix::sys::signal::{self, Signal};
use nix::unistd::Pid;

use crate::path;
use crate::settings::{settings_manager, Key};

#[derive(Default)]
pub struct Daemon {
    child: RefCell<Option<Child>>,
}

impl Daemon {
    pub async fn start(&self) -> anyhow::Result<()> {
        debug!("Start transmission daemon...");
        self.ensure_rpc_enabled();

        if self.child.borrow().is_some() {
            warn!("Daemon is already running!");
            return Ok(());
        }

        // Allow all addresses ("*") if remote access is enabled,
        // and not just localhost
        let remote_access = if settings_manager::boolean(Key::RemoteAccess) {
            "*"
        } else {
            "127.0.0.1,::1"
        };

        let args = [
            "-f",
            "--no-auth",
            "--config-dir",
            path::CONFIG.to_str().unwrap(),
            "--port",
            "9091",
            "--rpc-bind-address",
            "0.0.0.0",
            "--allowed",
            remote_access,
        ];
        debug!("Daemon args: {:#?}", args);
        let child = Command::new("transmission-daemon")
            .args(args)
            .stdout(Stdio::piped())
            .spawn()?;

        *self.child.borrow_mut() = Some(child);
        Ok(())
    }

    pub async fn stop(&self) -> anyhow::Result<()> {
        debug!("Stop transmission daemon...");
        let child = { self.child.try_borrow_mut()?.take() };

        match child {
            Some(mut child) => {
                let pid = Pid::from_raw(child.id().try_into().unwrap());
                signal::kill(pid, Signal::SIGTERM)?;

                let status = child.status().await?;
                debug!("Daemon stopped, status code: {}", status);
            }
            None => warn!("Daemon is not running, unable to stop it"),
        }

        Ok(())
    }

    pub fn is_running(&self) -> bool {
        self.child.borrow().is_some()
    }

    // Fragments-v1 (old Vala edition) had rpc disabled by default.
    // Fragments-v2 (Rust rewrite) needs RPC enabled to communicate with
    // transmission-daemon
    fn ensure_rpc_enabled(&self) {
        let config_path = Path::new(&*path::CONFIG).join("settings.json");

        match fs::read_to_string(&config_path) {
            Ok(data) => {
                if data.contains("\"rpc-enabled\": false") {
                    info!("RPC is disabled in settings.json. Enabling... ");
                    let updated = data.replace("\"rpc-enabled\": false", "\"rpc-enabled\": true");

                    // Write updated config file
                    if let Err(err) = fs::write(&config_path, updated) {
                        warn!(
                            "Cannot enable rpc, Fragments will probably not work: {}",
                            err.to_string()
                        )
                    }
                }
            }
            Err(err) => warn!("Can't ensure that rpc is enabled: {}", err.to_string()),
        };
    }
}
