// SPDX-License-Identifier: LicenseRef-Commercial
// Multi-Account Profile Switching — manage multiple Claude/provider accounts.

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

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AccountProfile {
    pub id: String,
    pub display_name: String,
    pub email: Option<String>,
    pub provider: String,
    pub config_dir: String,
    pub is_active: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ActiveAccount {
    pub profile_id: String,
    pub provider: String,
    pub config_dir: String,
}

/// List all configured account profiles across providers.
/// Scans ~/.config/agor/accounts.json for profile definitions.
#[tauri::command]
pub fn pro_list_accounts() -> Result<Vec<AccountProfile>, String> {
    let accounts_path = accounts_file_path()?;
    let active = load_active_id();

    if !accounts_path.exists() {
        // Return default account derived from Claude profiles
        let home = dirs::home_dir().unwrap_or_default();
        let default_dir = home.join(".claude").to_string_lossy().to_string();
        return Ok(vec![AccountProfile {
            id: "default".into(),
            display_name: "Default".into(),
            email: None,
            provider: "claude".into(),
            config_dir: default_dir,
            is_active: true,
        }]);
    }

    let content = std::fs::read_to_string(&accounts_path)
        .map_err(|e| format!("Failed to read accounts.json: {e}"))?;

    let mut profiles: Vec<AccountProfile> = serde_json::from_str(&content)
        .map_err(|e| format!("Failed to parse accounts.json: {e}"))?;

    for p in &mut profiles {
        p.is_active = p.id == active;
    }

    Ok(profiles)
}

/// Get the currently active account.
#[tauri::command]
pub fn pro_get_active_account() -> Result<ActiveAccount, String> {
    let profiles = pro_list_accounts()?;
    let active = profiles.iter()
        .find(|p| p.is_active)
        .or_else(|| profiles.first())
        .ok_or("No accounts configured")?;

    Ok(ActiveAccount {
        profile_id: active.id.clone(),
        provider: active.provider.clone(),
        config_dir: active.config_dir.clone(),
    })
}

/// Switch the active account. Updates ~/.config/agor/active-account.
#[tauri::command]
pub fn pro_set_active_account(profile_id: String) -> Result<ActiveAccount, String> {
    let profiles = pro_list_accounts()?;
    let target = profiles.iter()
        .find(|p| p.id == profile_id)
        .ok_or_else(|| format!("Account '{}' not found", profile_id))?;

    let active_path = active_account_path()?;
    std::fs::write(&active_path, &profile_id)
        .map_err(|e| format!("Failed to write active account: {e}"))?;

    Ok(ActiveAccount {
        profile_id: target.id.clone(),
        provider: target.provider.clone(),
        config_dir: target.config_dir.clone(),
    })
}

fn accounts_file_path() -> Result<PathBuf, String> {
    let config = agor_core::config::AppConfig::from_env();
    Ok(config.config_dir.join("accounts.json"))
}

fn active_account_path() -> Result<PathBuf, String> {
    let config = agor_core::config::AppConfig::from_env();
    Ok(config.config_dir.join("active-account"))
}

fn load_active_id() -> String {
    active_account_path()
        .ok()
        .and_then(|p| std::fs::read_to_string(p).ok())
        .map(|s| s.trim().to_string())
        .unwrap_or_else(|| "default".into())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_account_profile_serializes_camel_case() {
        let p = AccountProfile {
            id: "work".into(),
            display_name: "Work Account".into(),
            email: Some("work@example.com".into()),
            provider: "claude".into(),
            config_dir: "/home/user/.claude-work".into(),
            is_active: true,
        };
        let json = serde_json::to_string(&p).unwrap();
        assert!(json.contains("displayName"));
        assert!(json.contains("isActive"));
        assert!(json.contains("configDir"));
    }

    #[test]
    fn test_active_account_struct() {
        let a = ActiveAccount {
            profile_id: "test".into(),
            provider: "claude".into(),
            config_dir: "/tmp/test".into(),
        };
        let json = serde_json::to_string(&a).unwrap();
        assert!(json.contains("profileId"));
    }
}
