use serde::{Deserialize, Serialize};

pub const DEFAULT_CONTROL_SOCKET: &str = "/tmp/falcorn-control.sock";
pub const CONTROL_FRAME_MAGIC: [u8; 4] = *b"FLCC";
pub const CONTROL_PROTOCOL_VERSION: u8 = 1;
pub const CONTROL_FRAME_HEADER_LEN: usize = 12;
pub const CONTROL_MAX_PAYLOAD_LEN: usize = 1024 * 1024;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ControlFrameType {
    Subscribe = 1,
    Ack = 2,
    ActionRequest = 3,
    ActionResponse = 4,
    Error = 5,
    Ping = 6,
    Pong = 7,
}

impl ControlFrameType {
    pub fn from_u8(value: u8) -> Option<Self> {
        match value {
            1 => Some(Self::Subscribe),
            2 => Some(Self::Ack),
            3 => Some(Self::ActionRequest),
            4 => Some(Self::ActionResponse),
            5 => Some(Self::Error),
            6 => Some(Self::Ping),
            7 => Some(Self::Pong),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlSubscribeRequest {
    pub auth_token: Option<String>,
    pub client_name: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlSubscribeAck {
    pub protocol_version: u8,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlErrorFrame {
    pub code: String,
    pub message: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlPingFrame {
    pub ts_millis: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlPongFrame {
    pub ts_millis: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ActionKind {
    GetStatus,
    GetWorkers,
    ReloadConfig,
    ShowConfig,
    ScaleTo,
    RestartWorker,
    Shutdown,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionRequest {
    pub id: u64,
    pub action: ActionKind,
    pub payload: Option<ActionRequestPayload>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ActionStatus {
    Ok,
    Error,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionError {
    pub code: String,
    pub message: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StatusSnapshot {
    pub version: String,
    pub pid: u32,
    pub bind_addr: String,
    pub worker_count: usize,
    pub worker_class: String,
    pub app_module: String,
    pub app_callable: String,
    pub uptime_secs: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkerSnapshot {
    pub id: u32,
    pub pid: Option<i32>,
    pub state: String,
    pub restarts: u32,
    pub uptime_secs: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReloadConfigResult {
    pub applied: bool,
    pub message: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScaleToRequest {
    pub workers: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RestartWorkerRequest {
    pub id: Option<u32>,
    pub graceful: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ShutdownRequest {
    pub graceful: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReloadConfigRequest {
    pub path: Option<String>,
    pub rolling: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ActionRequestPayload {
    ScaleTo(ScaleToRequest),
    RestartWorker(RestartWorkerRequest),
    Shutdown(ShutdownRequest),
    ReloadConfig(ReloadConfigRequest),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ActionPayload {
    Status(StatusSnapshot),
    Workers(Vec<WorkerSnapshot>),
    ReloadConfig(ReloadConfigResult),
    Config(String),
    Message(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionResponse {
    pub id: u64,
    pub status: ActionStatus,
    pub payload: Option<ActionPayload>,
    pub error: Option<ActionError>,
}

#[derive(Debug, Clone, Copy)]
pub enum ControlAclMode {
    Off,
    SameUser,
}

#[derive(Debug)]
pub enum ControlCommand {
    ScaleTo {
        workers: usize,
        respond_to: std::sync::mpsc::Sender<CommandResult>,
    },
    RestartWorker {
        id: Option<u32>,
        graceful: bool,
        respond_to: std::sync::mpsc::Sender<CommandResult>,
    },
    Shutdown {
        graceful: bool,
        respond_to: std::sync::mpsc::Sender<CommandResult>,
    },
    ReloadConfig {
        path: String,
        rolling: bool,
        respond_to: std::sync::mpsc::Sender<CommandResult>,
    },
}

#[derive(Debug, Clone)]
pub struct CommandResult {
    pub ok: bool,
    pub message: String,
}
