Skip to content
use serde::{Deserialize, Serialize};

use crate::task::Task;

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "cmd", rename_all = "snake_case")]
pub enum Request {
    ListTasks,
    AddTask { name: String, duration_minutes: u32 },
    RemoveTask { index: usize },
    ToggleDone { index: usize },
    MarkDone { index: usize },
    ClearCompleted,
    StartTimer { index: usize },
    PauseTimer,
    ResumeTimer,
    StopTimer,
    Status,
    Shutdown,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TimerStatus {
    Idle,
    Running,
    Paused,
    Finished,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimerInfo {
    pub state: TimerStatus,
    pub task_index: Option<usize>,
    pub remaining_secs: u64,
    pub total_secs: u64,
}

impl Default for TimerInfo {
    fn default() -> Self {
        Self {
            state: TimerStatus::Idle,
            task_index: None,
            remaining_secs: 0,
            total_secs: 0,
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Response {
    pub ok: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tasks: Option<Vec<Task>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timer: Option<TimerInfo>,
}

impl Response {
    pub fn ok() -> Self {
        Self {
            ok: true,
            message: None,
            tasks: None,
            timer: None,
        }
    }

    pub fn ok_msg(msg: impl Into<String>) -> Self {
        Self {
            ok: true,
            message: Some(msg.into()),
            tasks: None,
            timer: None,
        }
    }

    pub fn error(msg: impl Into<String>) -> Self {
        Self {
            ok: false,
            message: Some(msg.into()),
            tasks: None,
            timer: None,
        }
    }

    #[must_use]
    pub fn with_tasks(mut self, tasks: Vec<Task>) -> Self {
        self.tasks = Some(tasks);
        self
    }

    #[must_use]
    pub fn with_timer(mut self, timer: TimerInfo) -> Self {
        self.timer = Some(timer);
        self
    }
}

pub fn socket_path() -> std::path::PathBuf {
    if let Some(runtime_dir) = std::env::var_os("XDG_RUNTIME_DIR") {
        std::path::PathBuf::from(runtime_dir).join("hyperfocus.sock")
    } else {
        std::path::PathBuf::from("/tmp").join("hyperfocus.sock")
    }
}