#![allow(dead_code)]

use crate::error::{AppError, AppResult};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
    pub backend_base_url: String,
    pub mdm_server_url: String,
    pub supabase_url: String,
    pub supabase_anon_key: String,
    /// Stable device identity known to the backend (UserDevice.deviceId).
    /// Filled after first successful device registration.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub device_id: Option<String>,
    /// Hardware-bound identity (UserDevice.hardwareId).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hardware_id: Option<String>,
}

impl Default for AppConfig {
    fn default() -> Self {
        Self {
            backend_base_url: "https://staging.rebreak.org".to_string(),
            mdm_server_url: "https://mdm.rebreak.org".to_string(),
            supabase_url: String::new(),
            supabase_anon_key: String::new(),
            device_id: None,
            hardware_id: None,
        }
    }
}

const KEYRING_SERVICE: &str = "org.rebreak.magic";
const KEYRING_ACCOUNT: &str = "magic-session";
const SESSION_FILE: &str = "session.json";
const DESKTOP_PROTECTION_FILE: &str = "desktop-protection.json";

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MagicSession {
    pub access_token: String,
    pub session_id: String,
    pub user_id: String,
    #[serde(with = "chrono::serde::ts_seconds")]
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub label: Option<String>,
}

impl MagicSession {
    pub fn new(access_token: String, session_id: String, label: Option<String>) -> Self {
        Self {
            access_token,
            session_id,
            user_id: String::new(),
            created_at: chrono::Utc::now(),
            label,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BinderConfig {
    #[serde(rename = "mdmServer")]
    pub mdm_server: String,
    #[serde(rename = "mdmUser")]
    pub mdm_user: String,
    #[serde(rename = "mdmApiKey")]
    pub mdm_api_key: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DesktopProtectionState {
    pub active: bool,
    pub platform: String,
    #[serde(with = "chrono::serde::ts_seconds")]
    pub activated_at: chrono::DateTime<chrono::Utc>,
}

impl AppConfig {
    pub fn config_dir() -> AppResult<PathBuf> {
        let dir = dirs::config_dir()
            .ok_or_else(|| AppError::new("Could not find config directory"))?
            .join("org.rebreak.magic");
        std::fs::create_dir_all(&dir)?;
        Ok(dir)
    }

    pub fn config_path() -> AppResult<PathBuf> {
        Ok(Self::config_dir()?.join("config.json"))
    }

    pub fn binder_config_path() -> AppResult<PathBuf> {
        Ok(dirs::config_dir()
            .ok_or_else(|| AppError::new("Could not find config directory"))?
            .join("rebreak-binder")
            .join("config.json"))
    }

    pub fn load_binder_config() -> AppResult<BinderConfig> {
        let path = Self::binder_config_path()?;
        if !path.exists() {
            return Err(AppError::new(
                "rebreak-binder config nicht gefunden. Bitte README → 'Config (lokal)'.".to_string(),
            ));
        }
        let json = std::fs::read_to_string(&path)?;
        serde_json::from_str(&json)
            .map_err(|e| AppError::new(format!("rebreak-binder config kaputt: {}", e)))
    }

    pub fn load() -> Self {
        match Self::config_path() {
            Ok(path) if path.exists() => {
                std::fs::read_to_string(&path)
                    .ok()
                    .and_then(|s| serde_json::from_str(&s).ok())
                    .unwrap_or_default()
            }
            _ => Self::default(),
        }
    }

    pub fn save(&self) -> AppResult<()> {
        let path = Self::config_path()?;
        let contents = serde_json::to_string_pretty(self)?;
        std::fs::write(path, contents)?;
        Ok(())
    }

    fn session_path() -> AppResult<PathBuf> {
        Ok(Self::config_dir()?.join(SESSION_FILE))
    }

    pub fn save_magic_session(session: &MagicSession) -> AppResult<()> {
        let path = Self::session_path()?;
        let json = serde_json::to_string_pretty(session)
            .map_err(|e| AppError::new(format!("Failed to serialize session: {}", e)))?;
        std::fs::write(&path, json)?;
        Ok(())
    }

    pub fn load_magic_session() -> AppResult<Option<MagicSession>> {
        let path = match Self::session_path() {
            Ok(p) => p,
            Err(_) => return Ok(None),
        };

        if !path.exists() {
            return Ok(None);
        }

        let json = std::fs::read_to_string(&path)?;
        if json.trim().is_empty() {
            return Ok(None);
        }

        let session = serde_json::from_str(&json)
            .map_err(|e| AppError::new(format!("Failed to parse session: {}", e)))?;
        Ok(Some(session))
    }

    pub fn clear_magic_session() -> AppResult<()> {
        let path = match Self::session_path() {
            Ok(p) => p,
            Err(_) => return Ok(()),
        };
        if path.exists() {
            std::fs::remove_file(&path)?;
        }
        Ok(())
    }

    fn desktop_protection_path() -> AppResult<PathBuf> {
        Ok(Self::config_dir()?.join(DESKTOP_PROTECTION_FILE))
    }

    pub fn save_desktop_protection(state: &DesktopProtectionState) -> AppResult<()> {
        let path = Self::desktop_protection_path()?;
        let json = serde_json::to_string_pretty(state)
            .map_err(|e| AppError::new(format!("Failed to serialize desktop protection state: {}", e)))?;
        std::fs::write(&path, json)?;
        Ok(())
    }

    pub fn load_desktop_protection() -> AppResult<Option<DesktopProtectionState>> {
        let path = match Self::desktop_protection_path() {
            Ok(p) => p,
            Err(_) => return Ok(None),
        };
        if !path.exists() {
            return Ok(None);
        }
        let json = std::fs::read_to_string(&path)?;
        if json.trim().is_empty() {
            return Ok(None);
        }
        let state = serde_json::from_str(&json)
            .map_err(|e| AppError::new(format!("Failed to parse desktop protection state: {}", e)))?;
        Ok(Some(state))
    }

    pub fn clear_desktop_protection() -> AppResult<()> {
        let path = match Self::desktop_protection_path() {
            Ok(p) => p,
            Err(_) => return Ok(()),
        };
        if path.exists() {
            std::fs::remove_file(&path)?;
        }
        Ok(())
    }

    pub fn set_device_id(&mut self, id: String) -> AppResult<()> {
        self.device_id = Some(id);
        self.save()
    }

    pub fn set_hardware_id(&mut self, id: String) -> AppResult<()> {
        self.hardware_id = Some(id);
        self.save()
    }
}
