use crate::daemon::{Answer, AnswerErr, Command as OtherCommand};
use crate::helper::run_path;
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use std::net::Shutdown;
use std::os::unix::net::UnixStream;
use std::time::Duration;

#[derive(Parser)]
#[command(name = "timers")]
/// A simple timer daemon/cli.
pub struct Cli {
    #[command(subcommand)]
    pub command: Command,

    #[arg(short, long)]
    #[clap(default_value_t = format!("{}/timers.socket", run_path()))]
    pub socket: String,
    
    #[arg(long)]
    pub json: bool
}

#[derive(Debug, Subcommand)]
pub enum Command {
    /// Run as daemon
    #[clap(visible_alias = "d")]
    Daemon {
        /// do not send notifications
        #[arg(short, long)]
        no_notify: bool,
        #[arg(short, long)]
        #[clap(default_value_t = format!("{}/timers.pid", run_path()))]
        pid_file: String,
    },
    /// Add a timer
    #[clap(visible_alias = "a")]
    Add {
        /// name of the timer
        name: String,
        /// duration of the timer
        duration: humantime::Duration,
    },
    /// List timers
    #[clap(visible_alias = "l")]
    List,
    /// Toggle timer
    #[clap(visible_alias = "t")]
    Toggle {
        /// name of the timer to toggle
        name: String,
    },
    /// Remove a timer
    #[clap(visible_alias = "r")]
    Remove {
        /// name of the timer to remove
        name: String,
    },
    /// Pomodoro specific command
    #[command(subcommand)]
    #[clap(visible_alias = "p")]
    Pomodoro(PomodoroCommand),

    /// Shell completions
    Completions {
        #[arg(value_enum)]
        shell: clap_complete_command::Shell,
    }
}

#[derive(Debug, Subcommand)]
pub enum PomodoroCommand {
    /// Start pomodoro
    #[clap(visible_alias = "s")]
    Start {
        /// duration to work for
        #[arg(long)]
        #[clap(default_value_t = Duration::from_secs(25 * 60).into())]
        work: humantime::Duration,

        /// duration for short pauses
        #[arg(long)]
        #[clap(default_value_t = Duration::from_secs(5 * 60).into())]
        pause: humantime::Duration,

        /// duration for long pauses
        #[arg(long)]
        #[clap(default_value_t = Duration::from_secs(10 * 60).into())]
        long_pause: humantime::Duration,

        /// number of short pauses till long pause
        #[arg(long)]
        #[clap(default_value_t = 3)]
        pauses_till_long: u64,
    },
    /// Stop the pomodoro
    #[clap(visible_alias = "p")]
    Remove,
    /// List the pomodoro settings and remaining duration
    #[clap(visible_alias = "l")]
    List,
    /// Toggle pomodoro
    #[clap(visible_alias = "t")]
    Toggle,
}

pub fn send_command(socket_path: &String, command: OtherCommand) -> Result<Answer> {
    let stream = UnixStream::connect(socket_path)
        .context(format!("Could not connect to socket {}!", socket_path))?;
    serde_cbor::to_writer(&stream, &command).context("Could not write command!")?;
    stream
        .shutdown(Shutdown::Write)
        .context("Could not shutdown write!")?;
    let answer: Result<Answer, AnswerErr> =
        serde_cbor::from_reader(&stream).context("Could not read answer!")?;
    Ok(answer?)
}