use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};

const APP_NAME: &str = "Lightify";
const CONFIG_FILE: &str = "lightify_config.json";
const TOKEN_FILE: &str = ".lightify_cache";

/// Persistent app configuration (client_id, preferences).
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Config {
    #[serde(default)]
    pub client_id: String,
    /// Chosen OS audio output device name. Empty / "default" = OS default.
    #[serde(default)]
    pub audio_output: String,
    /// Directory where downloaded tracks are saved. Empty = use bridge default.
    #[serde(default)]
    pub download_path: String,
}

/// OAuth token info — matches the spotipy cache format for backward compat.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenInfo {
    pub access_token: String,
    pub token_type: String,
    pub expires_in: i64,
    pub refresh_token: String,
    pub scope: String,
    pub expires_at: i64,
    #[serde(default)]
    pub cached_user_id: String,
    #[serde(default)]
    pub cached_display_name: String,
}

impl TokenInfo {
    pub fn is_expired(&self) -> bool {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs() as i64;
        now >= self.expires_at - 60 // 60-second buffer
    }
}

/// Resolve the writable data directory.
pub fn data_dir() -> PathBuf {
    // Check env override
    if let Ok(val) = std::env::var("LIGHTIFY_DATA_DIR") {
        let p = PathBuf::from(val.trim());
        if !p.as_os_str().is_empty() {
            let _ = std::fs::create_dir_all(&p);
            return p;
        }
    }

    // Platform default
    if let Some(base) = dirs::data_dir() {
        let p = base.join(APP_NAME);
        let _ = std::fs::create_dir_all(&p);
        return p;
    }

    // Fallback: next to executable
    let p = std::env::current_exe()
        .unwrap_or_else(|_| PathBuf::from("."))
        .parent()
        .unwrap_or(Path::new("."))
        .join(format!(".{}-data", APP_NAME.to_lowercase()));
    let _ = std::fs::create_dir_all(&p);
    p
}

pub fn load_config(dir: &Path) -> Config {
    let path = dir.join(CONFIG_FILE);
    match std::fs::read_to_string(&path) {
        Ok(text) => serde_json::from_str(&text).unwrap_or_default(),
        Err(_) => Config::default(),
    }
}

pub fn save_config(dir: &Path, cfg: &Config) {
    let path = dir.join(CONFIG_FILE);
    if let Ok(json) = serde_json::to_string_pretty(cfg) {
        let _ = std::fs::write(path, json);
    }
}

pub fn load_token(dir: &Path) -> Option<TokenInfo> {
    let path = dir.join(TOKEN_FILE);
    let text = std::fs::read_to_string(&path).ok()?;
    serde_json::from_str(&text).ok()
}

pub fn save_token(dir: &Path, token: &TokenInfo) {
    let path = dir.join(TOKEN_FILE);
    if let Ok(json) = serde_json::to_string_pretty(token) {
        let _ = std::fs::write(path, json);
    }
}

pub fn delete_token(dir: &Path) {
    let path = dir.join(TOKEN_FILE);
    let _ = std::fs::remove_file(path);
}
