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

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

use crate::config_state::ConfigState;
use crate::dto::{PublicBrandResp, SetSettingParams, ThemeResp};
use crate::error::ConfigError;
use crate::service::setting_service::SettingService;

/// 默认主题配置。
fn default_theme() -> ThemeResp {
    ThemeResp {
        primary_color: None,
        logo_url: None,
        sidebar_style: None,
        brand_name: Some("HMS 健康管理平台".into()),
        brand_slogan: Some("新一代健康管理平台".into()),
        brand_features: Some("患者管理 · 健康监测 · 随访管理 · AI 智能分析".into()),
        brand_copyright: Some("HMS 健康管理平台 · ©汕头市智界科技有限公司".into()),
    }
}

#[utoipa::path(
    get,
    path = "/api/v1/themes",
    responses(
        (status = 200, description = "成功", body = ApiResponse<ThemeResp>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
    ),
    security(("bearer_auth" = [])),
    tag = "主题设置"
)]
/// GET /api/v1/theme
///
/// 获取当前租户的主题配置。
/// 主题配置存储在 settings 表中，key 为 "theme"，scope 为 "tenant"。
/// 当没有任何主题配置时，返回默认主题（所有字段为 null）。
/// 需要 `theme.read` 权限。
pub async fn get_theme<S>(
    State(state): State<ConfigState>,
    Extension(ctx): Extension<TenantContext>,
) -> Result<JsonResponse<ApiResponse<ThemeResp>>, AppError>
where
    ConfigState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "theme.read")?;

    let theme = match SettingService::get("theme", "tenant", &None, ctx.tenant_id, &state.db).await
    {
        Ok(setting) => serde_json::from_value(setting.setting_value)
            .map_err(|e| AppError::Validation(format!("主题配置解析失败: {e}")))?,
        Err(ConfigError::NotFound(_)) => default_theme(),
        Err(e) => return Err(e.into()),
    };

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

#[utoipa::path(
    put,
    path = "/api/v1/themes",
    request_body = ThemeResp,
    responses(
        (status = 200, description = "成功", body = ApiResponse<ThemeResp>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
    ),
    security(("bearer_auth" = [])),
    tag = "主题设置"
)]
/// PUT /api/v1/theme
///
/// 更新当前租户的主题配置。
/// 将主题配置序列化为 JSON 存储到 settings 表。
/// 需要 `theme.update` 权限。
pub async fn update_theme<S>(
    State(state): State<ConfigState>,
    Extension(ctx): Extension<TenantContext>,
    Json(req): Json<ThemeResp>,
) -> Result<JsonResponse<ApiResponse<ThemeResp>>, AppError>
where
    ConfigState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "theme.update")?;

    let value = serde_json::to_value(&req)
        .map_err(|e| AppError::Validation(format!("主题配置序列化失败: {e}")))?;

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

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

#[utoipa::path(
    get,
    path = "/api/v1/public/brand",
    responses(
        (status = 200, description = "成功", body = ApiResponse<PublicBrandResp>),
    ),
    tag = "主题设置"
)]
/// GET /api/v1/public/brand
///
/// 获取公开品牌信息（无需认证）。
pub async fn get_public_brand() -> JsonResponse<ApiResponse<PublicBrandResp>> {
    let defaults = default_theme();
    JsonResponse(ApiResponse::ok(PublicBrandResp {
        brand_name: defaults
            .brand_name
            .unwrap_or_else(|| "HMS 健康管理平台".into()),
        brand_slogan: defaults
            .brand_slogan
            .unwrap_or_else(|| "新一代健康管理平台".into()),
        brand_features: defaults
            .brand_features
            .unwrap_or_else(|| "患者管理 · 健康监测 · 随访管理 · AI 智能分析".into()),
        brand_copyright: defaults
            .brand_copyright
            .unwrap_or_else(|| "HMS 健康管理平台 · ©汕头市智界科技有限公司".into()),
    }))
}

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

    #[test]
    fn default_theme_has_brand_defaults() {
        let theme = default_theme();
        assert!(theme.primary_color.is_none());
        assert!(theme.logo_url.is_none());
        assert!(theme.sidebar_style.is_none());
        assert_eq!(theme.brand_name, Some("HMS 健康管理平台".to_string()));
        assert_eq!(theme.brand_slogan, Some("新一代健康管理平台".to_string()));
        assert!(theme.brand_features.is_some());
        assert!(theme.brand_copyright.is_some());
    }

    #[test]
    fn theme_resp_serde_roundtrip() {
        let theme = ThemeResp {
            primary_color: Some("#1890ff".to_string()),
            logo_url: None,
            sidebar_style: Some("dark".to_string()),
            brand_name: Some("测试平台".to_string()),
            brand_slogan: None,
            brand_features: None,
            brand_copyright: None,
        };
        let json = serde_json::to_string(&theme).unwrap();
        let back: ThemeResp = serde_json::from_str(&json).unwrap();
        assert_eq!(back.primary_color, Some("#1890ff".to_string()));
        assert_eq!(back.brand_name, Some("测试平台".to_string()));
        assert!(back.brand_slogan.is_none());
    }
}
