//! Organization management operations for the Arma 3 server extension.
//!
//! Provides Arma 3 extension commands for organization data storage, retrieval, and updates.
//! Handles SQF command mapping and parameter validation.

use arma_rs::Group;
use forge_repositories::RedisOrgRepository;
use forge_services::OrgService;
use std::sync::LazyLock;

use crate::adapters::ExtensionRedisClient;
use crate::log::log;

/// Global organization service instance.
///
/// Lazily initialized singleton combining Redis adapter, repository, and service layers.
static ORG_SERVICE: LazyLock<OrgService<RedisOrgRepository<ExtensionRedisClient>>> =
    LazyLock::new(|| {
        let redis_client = ExtensionRedisClient::new();
        let repository = RedisOrgRepository::new(redis_client);
        OrgService::new(repository)
    });

/// Creates the Arma 3 command group for organization operations.
///
/// Registers commands: `get`, `exists`, `create`, `update`, `delete`.
pub fn group() -> Group {
    Group::new()
        .command("get", get_org)
        .command("create", create_org)
        .command("update", update_org)
        .command("exists", org_exists)
        .command("delete", delete_org)
        .group(
            "members",
            Group::new()
                .command("get", get_members)
                .command("add", add_member)
                .command("remove", remove_member),
        )
}

// ============================================================================
// Organization Asset Operations
// ============================================================================

/// Retrieves an organization by key/ID.
///
/// Returns the organization as JSON or an error message if not found.
pub fn get_org(key: String) -> String {
    log(
        "org",
        "DEBUG",
        &format!("Getting organization for key: {}", key),
    );

    match ORG_SERVICE.get_org(key.clone()) {
        Ok(org) => {
            log(
                "org",
                "INFO",
                &format!("Successfully retrieved organization: {}", key),
            );
            match serde_json::to_string(&org) {
                Ok(json) => {
                    log("org", "DEBUG", &format!("Serialized org to JSON: {}", json));
                    json
                }
                Err(e) => {
                    let error_msg = format!("Error: Failed to serialize org: {}", e);
                    log("org", "ERROR", &error_msg);
                    error_msg
                }
            }
        }
        Err(e) => {
            let error_msg = format!("Error: {}", e);
            log(
                "org",
                "ERROR",
                &format!("Failed to get organization '{}': {}", key, e),
            );
            error_msg
        }
    }
}

/// Checks if an organization exists in the database.
///
/// Returns "true" if the organization exists, "false" otherwise.
pub fn org_exists(key: String) -> String {
    match ORG_SERVICE.org_exists(key) {
        Ok(exists) => if exists { "true" } else { "false" }.to_string(),
        Err(_) => "false".to_string(),
    }
}

/// Creates a new organization with the provided JSON data.
///
/// Resolves key to ID, validates JSON data, and persists the new organization.
pub fn create_org(key: String, json_data: String) -> String {
    log(
        "org",
        "DEBUG",
        &format!(
            "Creating organization for key: {} with data: {}",
            key, json_data
        ),
    );

    match ORG_SERVICE.create_org(key.clone(), json_data) {
        Ok(org) => {
            log(
                "org",
                "INFO",
                &format!("Successfully created organization: {}", key),
            );
            match serde_json::to_string(&org) {
                Ok(json) => {
                    log("org", "DEBUG", &format!("Serialized org to JSON: {}", json));
                    json
                }
                Err(e) => {
                    let error_msg = format!("Error: Failed to serialize org: {}", e);
                    log("org", "ERROR", &error_msg);
                    error_msg
                }
            }
        }
        Err(e) => {
            let error_msg = format!("Error: {}", e);
            log(
                "org",
                "ERROR",
                &format!("Failed to create organization '{}': {}", key, e),
            );
            error_msg
        }
    }
}

/// Updates an existing organization with JSON data.
///
/// Resolves key to ID, applies partial updates from JSON, and persists changes.
pub fn update_org(key: String, json_update: String) -> String {
    match ORG_SERVICE.update_org(key, json_update) {
        Ok(org) => match serde_json::to_string(&org) {
            Ok(json) => json,
            Err(e) => format!("Error: Failed to serialize org: {}", e),
        },
        Err(e) => format!("Error: {}", e),
    }
}

/// Permanently deletes an organization.
///
/// Resolves key to ID and removes the organization and associated data.
pub fn delete_org(key: String) -> String {
    match ORG_SERVICE.delete_org(key) {
        Ok(_) => "OK".to_string(),
        Err(e) => format!("Error: {}", e),
    }
}

// ============================================================================
// Member Operations
// ============================================================================

/// Retrieves organization members as a JSON object.
///
/// Returns a map of member UIDs to names. Returns empty object if not found.
pub fn get_members(key: String) -> String {
    match ORG_SERVICE.get_members(key) {
        Ok(members) => match serde_json::to_string(&members) {
            Ok(json) => json,
            Err(_) => "{}".to_string(),
        },
        Err(_) => "{}".to_string(),
    }
}

/// Adds a new member to an organization by their UID.
///
/// Resolves organization key to ID and adds the member UID.
/// Redis sets automatically prevent duplicate members.
pub fn add_member(key: String, member_uid: String) -> String {
    match ORG_SERVICE.add_member(key, member_uid) {
        Ok(_) => "OK".to_string(),
        Err(e) => format!("Error: {}", e),
    }
}

/// Removes a member from an organization by their UID.
///
/// Resolves organization key to ID and removes the member UID.
pub fn remove_member(key: String, member_uid: String) -> String {
    match ORG_SERVICE.remove_member(key, member_uid) {
        Ok(_) => "OK".to_string(),
        Err(e) => format!("Error: {}", e),
    }
}
