//! Generated code access layer
//!
//! This module provides PAP-compliant access to generated resources using
//! the core-types trait system. Implementation projects provide concrete
//! trait implementations, while core-lib provides fallback implementations.

use std::{collections::HashMap, sync::OnceLock};

use rustelo_core_types::{
    ComponentResult, ContentProvider, PageProvider, RouteResolver, RoutingResult,
};

/// Trait for accessing generated content types
/// Implementation projects should provide concrete implementations
pub trait GeneratedContentAccess {
    /// Get all available content types from generated code
    fn get_all_content_types() -> Vec<String>;

    /// Get enabled content types only
    fn get_enabled_content_types() -> Vec<String>;

    /// Create content kind registry from generated data
    fn create_content_kind_registry() -> crate::ContentKindRegistry;
}

/// Trait for accessing generated configuration
/// Implementation projects should provide concrete implementations
pub trait GeneratedConfigAccess {
    /// Get server content URL from generated config
    fn get_server_content_url() -> String;

    /// Get base URL from generated config
    fn get_base_url() -> String;

    /// Check if running in production mode
    fn is_production() -> bool;
}

/// Fallback implementation for development/testing
pub struct FallbackGeneratedAccess;

impl GeneratedContentAccess for FallbackGeneratedAccess {
    fn get_all_content_types() -> Vec<String> {
        vec!["page".to_string(), "blog".to_string(), "docs".to_string()]
    }

    fn get_enabled_content_types() -> Vec<String> {
        Self::get_all_content_types()
    }

    fn create_content_kind_registry() -> crate::ContentKindRegistry {
        crate::ContentKindRegistry::new()
    }
}

impl GeneratedConfigAccess for FallbackGeneratedAccess {
    fn get_server_content_url() -> String {
        std::env::var("SERVER_CONTENT_URL").unwrap_or_else(|_| "/content".to_string())
    }

    fn get_base_url() -> String {
        std::env::var("BASE_URL").unwrap_or_else(|_| "http://localhost:3000".to_string())
    }

    fn is_production() -> bool {
        std::env::var("ENVIRONMENT")
            .map(|e| e == "production")
            .unwrap_or(false)
    }
}

// Global registry populated by implementation projects at startup
static CONTENT_KIND_REGISTRY: OnceLock<crate::ContentKindRegistry> = OnceLock::new();

/// Override for server content URL — seeded at startup from build-time config.
/// Checked first by `generated_config::get_server_content_url()` before falling
/// back to the `SERVER_CONTENT_URL` env var. Required in WASM where env vars
/// are always absent.
static SERVER_CONTENT_URL_OVERRIDE: OnceLock<String> = OnceLock::new();

/// Register content kind configs from the implementation project.
///
/// Must be called at server startup (before any request is served) and on
/// WASM init. Subsequent calls after the first are silently ignored.
pub fn register_content_kind_registry(registry: crate::ContentKindRegistry) {
    let _ = CONTENT_KIND_REGISTRY.set(registry);
}

/// Register the server content URL from the implementation project's build-time
/// config.
///
/// Must be called before any content fetch (server startup or WASM init).
/// Subsequent calls after the first are silently ignored.
pub fn register_server_content_url(url: &str) {
    let _ = SERVER_CONTENT_URL_OVERRIDE.set(url.to_string());
}

// Public functions that use the fallback by default
// Implementation projects can override these by providing their own
// implementations

/// Get all content types from the registered registry, falling back to the
/// development defaults when `register_content_kind_registry` has not been
/// called.
pub fn get_all_content_types() -> Vec<String> {
    CONTENT_KIND_REGISTRY
        .get()
        .map(|r| r.kinds.keys().cloned().collect())
        .unwrap_or_else(FallbackGeneratedAccess::get_all_content_types)
}

/// Get enabled content types from the registered registry, falling back to the
/// development defaults when `register_content_kind_registry` has not been
/// called.
pub fn get_enabled_content_types() -> Vec<String> {
    CONTENT_KIND_REGISTRY
        .get()
        .map(|r| {
            r.kinds
                .values()
                .filter(|c| c.enabled)
                .map(|c| c.name.clone())
                .collect()
        })
        .unwrap_or_else(FallbackGeneratedAccess::get_enabled_content_types)
}

/// Return the registered content kind registry, or an empty fallback.
///
/// Returns the registry set via `register_content_kind_registry()` if it has
/// been populated; falls back to `FallbackGeneratedAccess` otherwise.
pub fn create_content_kind_registry() -> crate::ContentKindRegistry {
    CONTENT_KIND_REGISTRY
        .get()
        .cloned()
        .unwrap_or_else(FallbackGeneratedAccess::create_content_kind_registry)
}

/// Generated config module (to replace the missing generated_config calls)
pub mod generated_config {
    use super::{FallbackGeneratedAccess, GeneratedConfigAccess};

    /// Get server content URL.
    ///
    /// Returns the value registered via `register_server_content_url()` if set,
    /// otherwise falls back to the `SERVER_CONTENT_URL` env var (defaults to
    /// `/content`). Use `register_server_content_url()` at startup to
    /// ensure WASM works correctly.
    pub fn get_server_content_url() -> String {
        super::SERVER_CONTENT_URL_OVERRIDE
            .get()
            .cloned()
            .unwrap_or_else(FallbackGeneratedAccess::get_server_content_url)
    }

    /// Get base URL using fallback implementation
    /// Implementation projects should override this
    pub fn get_base_url() -> String {
        FallbackGeneratedAccess::get_base_url()
    }

    /// Check if running in production mode using fallback implementation
    /// Implementation projects should override this
    pub fn is_production() -> bool {
        FallbackGeneratedAccess::is_production()
    }
}
