use std::sync::atomic::AtomicU64;
use std::sync::Arc;

use axum::extract::FromRef;
use sea_orm::DatabaseConnection;

use crate::config::AppConfig;
use erp_core::events::EventBus;
use erp_core::module::ModuleRegistry;

/// Axum shared application state.
/// All handlers access database connections, configuration, etc. through `State<AppState>`.
#[derive(Clone)]
pub struct AppState {
    pub db: DatabaseConnection,
    pub config: AppConfig,
    pub event_bus: EventBus,
    pub module_registry: ModuleRegistry,
    pub redis: redis::Client,
    /// 实际的默认租户 ID，从数据库种子数据中获取。
    pub default_tenant_id: uuid::Uuid,
    /// 插件引擎
    pub plugin_engine: erp_plugin::engine::PluginEngine,
    /// 插件实体缓存
    pub plugin_entity_cache: moka::sync::Cache<String, erp_plugin::state::EntityInfo>,
    /// PII 加密服务（KEK + DEK 管理）
    pub pii_crypto: erp_core::crypto::PiiCrypto,
    /// 定时任务心跳（unix timestamp secs），每个 cron tick 更新
    pub cron_heartbeat: Arc<AtomicU64>,
}

/// Allow handlers to extract `DatabaseConnection` directly from `State<AppState>`.
impl FromRef<AppState> for DatabaseConnection {
    fn from_ref(state: &AppState) -> Self {
        state.db.clone()
    }
}

/// Allow handlers to extract `EventBus` directly from `State<AppState>`.
impl FromRef<AppState> for EventBus {
    fn from_ref(state: &AppState) -> Self {
        state.event_bus.clone()
    }
}

/// Allow erp-auth handlers to extract their required state without depending on erp-server.
///
/// This bridges the gap: erp-auth defines `AuthState` with the fields it needs,
/// and erp-server fills them from `AppState`.
impl FromRef<AppState> for erp_auth::AuthState {
    fn from_ref(state: &AppState) -> Self {
        use erp_auth::auth_state::parse_ttl;

        Self {
            db: state.db.clone(),
            event_bus: state.event_bus.clone(),
            jwt_secret: state.config.jwt.secret.clone(),
            access_ttl_secs: parse_ttl(&state.config.jwt.access_token_ttl),
            refresh_ttl_secs: parse_ttl(&state.config.jwt.refresh_token_ttl),
            default_tenant_id: state.default_tenant_id,
            redis: Some(state.redis.clone()),
            crypto: state.pii_crypto.clone(),
        }
    }
}

/// Allow erp-config handlers to extract their required state without depending on erp-server.
impl FromRef<AppState> for erp_config::ConfigState {
    fn from_ref(state: &AppState) -> Self {
        Self {
            db: state.db.clone(),
            event_bus: state.event_bus.clone(),
        }
    }
}

/// Allow erp-workflow handlers to extract their required state without depending on erp-server.
impl FromRef<AppState> for erp_workflow::WorkflowState {
    fn from_ref(state: &AppState) -> Self {
        Self {
            db: state.db.clone(),
            event_bus: state.event_bus.clone(),
        }
    }
}

/// Allow erp-message handlers to extract their required state without depending on erp-server.
impl FromRef<AppState> for erp_message::MessageState {
    fn from_ref(state: &AppState) -> Self {
        Self {
            db: state.db.clone(),
            event_bus: state.event_bus.clone(),
        }
    }
}

/// Allow erp-plugin handlers to extract their required state.
impl FromRef<AppState> for erp_plugin::state::PluginState {
    fn from_ref(state: &AppState) -> Self {
        Self {
            db: state.db.clone(),
            event_bus: state.event_bus.clone(),
            engine: state.plugin_engine.clone(),
            entity_cache: state.plugin_entity_cache.clone(),
        }
    }
}
