use axum::Extension;
use axum::extract::{FromRef, Json, Path, State};
use axum::response::Json as JsonResponse;

use erp_core::error::AppError;
use erp_core::rbac::require_permission;
use erp_core::types::{ApiResponse, Pagination, TenantContext};

use crate::config_state::ConfigState;
use crate::dto::{LanguageResp, SetSettingParams, UpdateLanguageReq};
use crate::service::setting_service::SettingService;

#[utoipa::path(
    get,
    path = "/api/v1/languages",
    responses(
        (status = 200, description = "成功", body = ApiResponse<Vec<LanguageResp>>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
    ),
    security(("bearer_auth" = [])),
    tag = "语言管理"
)]
/// GET /api/v1/languages
///
/// 获取当前租户的语言配置列表。
/// 查询 scope 为 "platform" 的设置，过滤 key 以 "language." 开头的记录。
/// 需要 `language.list` 权限。
pub async fn list_languages<S>(
    State(state): State<ConfigState>,
    Extension(ctx): Extension<TenantContext>,
) -> Result<JsonResponse<ApiResponse<Vec<LanguageResp>>>, AppError>
where
    ConfigState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "language.list")?;

    let pagination = Pagination {
        page: Some(1),
        page_size: Some(100),
    };

    let (settings, _total) =
        SettingService::list_by_scope("platform", &None, ctx.tenant_id, &pagination, &state.db)
            .await?;

    let languages: Vec<LanguageResp> = settings
        .into_iter()
        .filter(|s| s.setting_key.starts_with("language."))
        .filter_map(|s| {
            let code = s.setting_key.strip_prefix("language.")?.to_string();
            let name = s
                .setting_value
                .get("name")
                .and_then(|v| v.as_str())
                .unwrap_or(&code)
                .to_string();
            let is_active = s
                .setting_value
                .get("is_active")
                .and_then(|v| v.as_bool())
                .unwrap_or(true);
            Some(LanguageResp {
                code,
                name,
                is_active,
            })
        })
        .collect();

    Ok(JsonResponse(ApiResponse::ok(languages)))
}

#[utoipa::path(
    put,
    path = "/api/v1/languages/{code}",
    params(("code" = String, Path, description = "语言编码")),
    request_body = UpdateLanguageReq,
    responses(
        (status = 200, description = "成功", body = ApiResponse<LanguageResp>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
    ),
    security(("bearer_auth" = [])),
    tag = "语言管理"
)]
/// PUT /api/v1/languages/:code
///
/// 更新指定语言配置的激活状态。
/// 语言配置存储在 settings 表中，key 为 "language.{code}"，scope 为 "platform"。
/// 需要 `language.update` 权限。
pub async fn update_language<S>(
    State(state): State<ConfigState>,
    Extension(ctx): Extension<TenantContext>,
    Path(code): Path<String>,
    Json(req): Json<UpdateLanguageReq>,
) -> Result<JsonResponse<ApiResponse<LanguageResp>>, AppError>
where
    ConfigState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "language.update")?;

    let key = format!("language.{}", code);
    let mut value = serde_json::json!({"is_active": req.is_active});
    if let Some(ref name) = req.name {
        value["name"] = serde_json::Value::String(name.clone());
    }

    SettingService::set(
        SetSettingParams {
            key: key.clone(),
            scope: "platform".to_string(),
            scope_id: None,
            value,
            version: None,
        },
        ctx.tenant_id,
        ctx.user_id,
        &state.db,
        &state.event_bus,
    )
    .await?;

    // 从返回的 SettingResp 中读取实际值
    let updated = SettingService::get(&key, "platform", &None, ctx.tenant_id, &state.db).await?;

    // 尝试从 value 中提取 name，否则用 code 作为默认名称
    let name = updated
        .setting_value
        .get("name")
        .and_then(|v| v.as_str())
        .unwrap_or(&code)
        .to_string();

    Ok(JsonResponse(ApiResponse::ok(LanguageResp {
        code,
        name,
        is_active: req.is_active,
    })))
}
