use anyhow::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};

/// Discovered server from a panel's auto-discovery
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscoveredServer {
    pub panel_server_id: String,
    pub name: String,
    pub ip: Option<String>,
    pub port: Option<i32>,
    pub game_port: Option<i32>,
    pub status: String,
}

/// Server status from panel query
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerStatus {
    pub is_running: bool,
    pub cpu_usage: Option<f64>,
    pub memory_usage_mb: Option<i64>,
    pub uptime_seconds: Option<i64>,
}

/// File entry from directory listing
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileEntry {
    pub name: String,
    pub path: String,
    pub is_directory: bool,
    pub size_bytes: Option<i64>,
    pub modified_at: Option<String>,
}

/// The core abstraction for server hosting panels.
///
/// Each panel type (AMP, Pterodactyl, Companion Agent) implements this trait.
/// The wipe engine, scheduler, and all server management operations call
/// through this interface — they never know or care which panel is backing
/// the server.
#[async_trait]
pub trait PanelAdapter: Send + Sync {
    /// Test that the panel connection is working
    async fn test_connection(&self) -> Result<bool>;

    /// Discover all game servers managed by this panel
    async fn discover_servers(&self) -> Result<Vec<DiscoveredServer>>;

    /// Get the current status of a server
    async fn get_server_status(&self, server_id: &str) -> Result<ServerStatus>;

    /// Start a stopped server
    async fn start_server(&self, server_id: &str) -> Result<()>;

    /// Stop a running server
    async fn stop_server(&self, server_id: &str) -> Result<()>;

    /// Restart a server (stop + start)
    async fn restart_server(&self, server_id: &str) -> Result<()>;

    /// Send a console command to the server
    async fn send_command(&self, server_id: &str, command: &str) -> Result<String>;

    /// Read a file from the server filesystem
    async fn get_file(&self, server_id: &str, path: &str) -> Result<Vec<u8>>;

    /// Write a file to the server filesystem
    async fn put_file(&self, server_id: &str, path: &str, data: &[u8]) -> Result<()>;

    /// Delete a file from the server filesystem
    async fn delete_file(&self, server_id: &str, path: &str) -> Result<()>;

    /// List files in a directory on the server
    async fn list_files(&self, server_id: &str, path: &str) -> Result<Vec<FileEntry>>;

    /// Trigger a SteamCMD update on the server
    async fn trigger_steam_update(&self, server_id: &str) -> Result<()>;
}
