use std::{
    path::PathBuf,
    sync::{Arc, RwLock},
    time::Duration,
};

use clap::Parser;
use serde::{Deserialize, Serialize};

#[derive(Parser, Debug)]
#[command(author, version, about)]
pub(crate) struct Cli {
    #[arg(long, default_value = "0.0.0.0:8080")]
    pub(crate) bind: String,
    #[arg(long, default_value = "/config")]
    pub(crate) config_dir: PathBuf,
    #[arg(long)]
    pub(crate) device: Option<String>,
    #[arg(long)]
    pub(crate) usb: Option<String>,
    #[arg(long)]
    pub(crate) simulate: bool,
    #[arg(long)]
    pub(crate) write_only: bool,
    #[arg(long)]
    pub(crate) disable_display: bool,
}

#[derive(Clone)]
pub(crate) struct AppState {
    pub(crate) monitor_path: PathBuf,
    pub(crate) image_dir: PathBuf,
    pub(crate) display_status: Arc<RwLock<DisplayStatus>>,
}

#[derive(Clone)]
pub(crate) struct DisplayConfig {
    pub(crate) device: Option<String>,
    pub(crate) usb: Option<String>,
    pub(crate) simulate: bool,
    pub(crate) write_only: bool,
    pub(crate) native_enabled: bool,
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub(crate) struct RotationSnapshot {
    pub(crate) custom_panel: bool,
    pub(crate) switch_time: u32,
    pub(crate) specs_enabled: bool,
    pub(crate) memes_enabled: bool,
    pub(crate) gifs_enabled: bool,
    pub(crate) active_images: Vec<String>,
}

impl RotationSnapshot {
    pub(crate) fn rotation_active(&self) -> bool {
        self.custom_panel
            && (self.specs_enabled
                || ((self.memes_enabled || self.gifs_enabled) && !self.active_images.is_empty()))
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct GifFrameMeta {
    pub(crate) name: String,
    pub(crate) delay_ms: u32,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct GifSetManifest {
    pub(crate) kind: String,
    pub(crate) version: u32,
    pub(crate) label: String,
    pub(crate) preview: String,
    pub(crate) frames: Vec<GifFrameMeta>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct ActiveFrame {
    pub(crate) key: String,
    pub(crate) image_name: String,
    pub(crate) display_name: String,
    pub(crate) animated: bool,
}

#[derive(Clone, Debug)]
pub(crate) struct RotationSlot {
    pub(crate) total_duration: Duration,
    pub(crate) frames: Vec<(ActiveFrame, Duration)>,
}

#[derive(Clone, Serialize)]
pub(crate) struct StateResponse {
    pub(crate) monitor_path: String,
    pub(crate) image_dir: String,
    pub(crate) setup: SetupView,
    pub(crate) active_images: Vec<String>,
    pub(crate) images: Vec<ImageView>,
    pub(crate) display: DisplayStatus,
    pub(crate) system: SystemView,
}

#[derive(Clone, Serialize)]
pub(crate) struct SetupView {
    pub(crate) custom_panel: bool,
    pub(crate) switch_time: String,
    pub(crate) specs_enabled: bool,
    pub(crate) memes_enabled: bool,
    pub(crate) gifs_enabled: bool,
}

#[derive(Clone, Serialize)]
pub(crate) struct ImageView {
    pub(crate) name: String,
    pub(crate) label: String,
    pub(crate) size: u64,
    pub(crate) url: String,
    pub(crate) animated: bool,
    pub(crate) frame_count: usize,
}

#[derive(Clone, Debug, Default, Serialize)]
pub(crate) struct DisplayStatus {
    pub(crate) native_enabled: bool,
    pub(crate) connected: bool,
    pub(crate) mode: String,
    pub(crate) device: String,
    pub(crate) custom_panel: bool,
    pub(crate) specs_enabled: bool,
    pub(crate) memes_enabled: bool,
    pub(crate) gifs_enabled: bool,
    pub(crate) rotation_active: bool,
    pub(crate) switch_time: String,
    pub(crate) active_images: Vec<String>,
    pub(crate) current_image: Option<String>,
    pub(crate) last_error: Option<String>,
    pub(crate) updated_at: Option<String>,
}

#[derive(Clone, Debug, Serialize)]
pub(crate) struct SystemView {
    pub(crate) cpu_usage_percent: String,
    pub(crate) load_avg_one: String,
    pub(crate) load_avg_five: String,
    pub(crate) load_avg_fifteen: String,
    pub(crate) mem_usage_percent: String,
    pub(crate) mem_used: String,
    pub(crate) mem_total: String,
    pub(crate) swap_usage_percent: String,
    pub(crate) swap_used: String,
    pub(crate) swap_total: String,
    pub(crate) disk_usage_percent: String,
    pub(crate) disk_used: String,
    pub(crate) disk_total: String,
    pub(crate) cache_usage_percent: String,
    pub(crate) cache_used: String,
    pub(crate) cache_total: String,
    pub(crate) user_usage_percent: String,
    pub(crate) user_used: String,
    pub(crate) user_total: String,
    pub(crate) cpu_count: usize,
    pub(crate) process_count: usize,
    pub(crate) uptime: String,
    pub(crate) temperature_cpu: Option<String>,
    pub(crate) temperature_gpu: Option<String>,
}

#[derive(Deserialize)]
pub(crate) struct ActivateRequest {
    pub(crate) images: Vec<String>,
    pub(crate) switch_time: Option<u32>,
    pub(crate) specs_enabled: Option<bool>,
    pub(crate) memes_enabled: Option<bool>,
    pub(crate) gifs_enabled: Option<bool>,
}

#[derive(Deserialize)]
pub(crate) struct DeleteRequest {
    pub(crate) name: String,
}

#[derive(Serialize)]
pub(crate) struct ErrorResponse {
    pub(crate) error: String,
}
