use axum::Extension;
use axum::extract::{FromRef, Multipart, Path, Query, State};
use axum::response::Json;
use uuid::Uuid;
use validator::Validate;

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

use crate::dto::{PluginHealthResp, PluginListParams, PluginResp, UpdatePluginConfigReq};
use crate::service::PluginService;
use crate::state::PluginState;

#[utoipa::path(
    post,
    path = "/api/v1/admin/plugins/upload",
    request_body(content_type = "multipart/form-data"),
    responses(
        (status = 200, description = "上传成功", body = ApiResponse<PluginResp>),
        (status = 401, description = "未授权"),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// POST /api/v1/admin/plugins/upload — 上传插件 (multipart: wasm + manifest)
pub async fn upload_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    mut multipart: Multipart,
) -> Result<Json<ApiResponse<PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;

    let mut wasm_binary: Option<Vec<u8>> = None;
    let mut manifest_toml: Option<String> = None;

    while let Some(field) = multipart
        .next_field()
        .await
        .map_err(|e| AppError::Validation(format!("Multipart 解析失败: {}", e)))?
    {
        let name = field.name().unwrap_or("");
        match name {
            "wasm" => {
                wasm_binary = Some(
                    field
                        .bytes()
                        .await
                        .map_err(|e| AppError::Validation(format!("读取 WASM 文件失败: {}", e)))?
                        .to_vec(),
                );
            }
            "manifest" => {
                let bytes = field
                    .bytes()
                    .await
                    .map_err(|e| AppError::Validation(format!("读取 Manifest 失败: {}", e)))?;
                let text = String::from_utf8(bytes.to_vec()).map_err(|e| {
                    AppError::Validation(format!("Manifest 不是有效的 UTF-8: {}", e))
                })?;
                manifest_toml = Some(text);
            }
            _ => {}
        }
    }

    let wasm = wasm_binary.ok_or_else(|| AppError::Validation("缺少 wasm 文件".to_string()))?;
    let manifest =
        manifest_toml.ok_or_else(|| AppError::Validation("缺少 manifest 文件".to_string()))?;

    let result =
        PluginService::upload(ctx.tenant_id, ctx.user_id, wasm, &manifest, &state.db).await?;

    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    get,
    path = "/api/v1/admin/plugins",
    params(PluginListParams),
    responses(
        (status = 200, description = "成功", body = ApiResponse<PaginatedResponse<PluginResp>>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// GET /api/v1/admin/plugins — 列表
pub async fn list_plugins<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Query(params): Query<PluginListParams>,
) -> Result<Json<ApiResponse<PaginatedResponse<PluginResp>>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.list")?;

    let pagination = Pagination {
        page: params.page,
        page_size: params.page_size,
    };

    let (plugins, total) = PluginService::list(
        ctx.tenant_id,
        pagination.page.unwrap_or(1),
        pagination.page_size.unwrap_or(20),
        params.status.as_deref(),
        params.search.as_deref(),
        &state.db,
    )
    .await?;

    Ok(Json(ApiResponse::ok(PaginatedResponse {
        data: plugins,
        total,
        page: pagination.page.unwrap_or(1),
        page_size: pagination.page_size.unwrap_or(20),
        total_pages: (total as f64 / pagination.page_size.unwrap_or(20) as f64).ceil() as u64,
    })))
}

#[utoipa::path(
    get,
    path = "/api/v1/admin/plugins/{id}",
    responses(
        (status = 200, description = "成功", body = ApiResponse<PluginResp>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// GET /api/v1/admin/plugins/{id} — 详情
pub async fn get_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.list")?;
    let result = PluginService::get_by_id(id, ctx.tenant_id, &state.db).await?;
    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    get,
    path = "/api/v1/admin/plugins/{id}/schema",
    responses(
        (status = 200, description = "成功"),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// GET /api/v1/admin/plugins/{id}/schema — 实体 schema
pub async fn get_plugin_schema<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<serde_json::Value>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.list")?;
    let schema = PluginService::get_schema(id, ctx.tenant_id, &state.db).await?;
    Ok(Json(ApiResponse::ok(schema)))
}

#[utoipa::path(
    post,
    path = "/api/v1/admin/plugins/{id}/install",
    responses(
        (status = 200, description = "安装成功", body = ApiResponse<PluginResp>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// POST /api/v1/admin/plugins/{id}/install — 安装
pub async fn install_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;
    let result = PluginService::install(id, ctx.tenant_id, ctx.user_id, &state.db, &state.engine)
        .await
        .map_err(|e| {
            tracing::error!(error = %e, "Install failed");
            e
        })?;
    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    post,
    path = "/api/v1/admin/plugins/{id}/enable",
    responses(
        (status = 200, description = "启用成功", body = ApiResponse<PluginResp>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// POST /api/v1/admin/plugins/{id}/enable — 启用
pub async fn enable_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;
    let result =
        PluginService::enable(id, ctx.tenant_id, ctx.user_id, &state.db, &state.engine).await?;
    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    post,
    path = "/api/v1/admin/plugins/{id}/disable",
    responses(
        (status = 200, description = "停用成功", body = ApiResponse<PluginResp>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// POST /api/v1/admin/plugins/{id}/disable — 停用
pub async fn disable_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;
    let result =
        PluginService::disable(id, ctx.tenant_id, ctx.user_id, &state.db, &state.engine).await?;
    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    post,
    path = "/api/v1/admin/plugins/{id}/uninstall",
    responses(
        (status = 200, description = "卸载成功", body = ApiResponse<PluginResp>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// POST /api/v1/admin/plugins/{id}/uninstall — 卸载
pub async fn uninstall_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;
    let result =
        PluginService::uninstall(id, ctx.tenant_id, ctx.user_id, &state.db, &state.engine).await?;
    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    delete,
    path = "/api/v1/admin/plugins/{id}",
    responses(
        (status = 200, description = "清除成功"),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// DELETE /api/v1/admin/plugins/{id} — 清除（软删除）
pub async fn purge_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<()>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;
    PluginService::purge(id, ctx.tenant_id, ctx.user_id, &state.db).await?;
    Ok(Json(ApiResponse::ok(())))
}

#[utoipa::path(
    get,
    path = "/api/v1/admin/plugins/{id}/health",
    responses(
        (status = 200, description = "健康检查", body = ApiResponse<PluginHealthResp>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// GET /api/v1/admin/plugins/{id}/health — 健康检查
pub async fn health_check_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<PluginHealthResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.list")?;
    let result = PluginService::health_check(id, ctx.tenant_id, &state.db, &state.engine).await?;
    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    get,
    path = "/api/v1/admin/plugins/{id}/metrics",
    responses(
        (status = 200, description = "运行时指标", body = ApiResponse<serde_json::Value>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// GET /api/v1/admin/plugins/{id}/metrics — 运行时指标
pub async fn get_plugin_metrics<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<serde_json::Value>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.list")?;

    // 通过 plugin_id 找到 manifest_id，再查询 metrics
    let manifest_id =
        crate::data_service::resolve_manifest_id(id, ctx.tenant_id, &state.db).await?;
    let metrics = state.engine.get_metrics(&manifest_id).await?;

    let avg_ms = if metrics.total_invocations > 0 {
        metrics.total_response_ms / metrics.total_invocations as f64
    } else {
        0.0
    };

    Ok(Json(ApiResponse::ok(serde_json::json!({
        "plugin_id": manifest_id,
        "total_invocations": metrics.total_invocations,
        "error_count": metrics.error_count,
        "avg_response_ms": avg_ms,
        "last_error": metrics.last_error,
        "last_invocation_at": metrics.last_invocation_at,
    }))))
}

#[utoipa::path(
    put,
    path = "/api/v1/admin/plugins/{id}/config",
    request_body = UpdatePluginConfigReq,
    responses(
        (status = 200, description = "更新成功", body = ApiResponse<PluginResp>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// PUT /api/v1/admin/plugins/{id}/config — 更新配置
pub async fn update_plugin_config<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
    Json(req): Json<UpdatePluginConfigReq>,
) -> Result<Json<ApiResponse<PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;
    req.validate()
        .map_err(|e| AppError::Validation(e.to_string()))?;
    let result = PluginService::update_config(
        id,
        ctx.tenant_id,
        ctx.user_id,
        req.config,
        req.version,
        &state.db,
        Some(&state.event_bus),
    )
    .await?;
    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    post,
    path = "/api/v1/admin/plugins/{id}/upgrade",
    request_body(content_type = "multipart/form-data"),
    responses(
        (status = 200, description = "升级成功", body = ApiResponse<PluginResp>),
    ),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// POST /api/v1/admin/plugins/{id}/upgrade — 热更新插件
///
/// 上传新版本 WASM + manifest，对比 schema 变更，执行增量 DDL，
/// 更新插件记录。失败时保持旧版本继续运行。
pub async fn upgrade_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
    mut multipart: Multipart,
) -> Result<Json<ApiResponse<PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;

    let mut wasm_binary: Option<Vec<u8>> = None;
    let mut manifest_toml: Option<String> = None;

    while let Some(field) = multipart
        .next_field()
        .await
        .map_err(|e| AppError::Validation(format!("Multipart 解析失败: {}", e)))?
    {
        let name = field.name().unwrap_or("");
        match name {
            "wasm" => {
                wasm_binary = Some(
                    field
                        .bytes()
                        .await
                        .map_err(|e| AppError::Validation(format!("读取 WASM 文件失败: {}", e)))?
                        .to_vec(),
                );
            }
            "manifest" => {
                let bytes = field
                    .bytes()
                    .await
                    .map_err(|e| AppError::Validation(format!("读取 Manifest 失败: {}", e)))?;
                manifest_toml = Some(String::from_utf8(bytes.to_vec()).map_err(|e| {
                    AppError::Validation(format!("Manifest 不是有效的 UTF-8: {}", e))
                })?);
            }
            _ => {}
        }
    }

    let wasm = wasm_binary.ok_or_else(|| AppError::Validation("缺少 wasm 文件".to_string()))?;
    let manifest =
        manifest_toml.ok_or_else(|| AppError::Validation("缺少 manifest 文件".to_string()))?;

    let result = PluginService::upgrade(
        id,
        ctx.tenant_id,
        ctx.user_id,
        wasm,
        &manifest,
        &state.db,
        &state.engine,
    )
    .await?;

    Ok(Json(ApiResponse::ok(result)))
}

#[utoipa::path(
    get,
    path = "/api/v1/admin/plugins/{id}/validate",
    params(("id" = Uuid, Path, description = "插件 ID")),
    responses((status = 200, description = "安全验证报告")),
    security(("bearer_auth" = [])),
    tag = "插件管理"
)]
/// GET /api/v1/admin/plugins/{id}/validate — 获取插件安全验证报告
pub async fn validate_plugin<S>(
    State(state): State<PluginState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<crate::plugin_validator::ValidationReport>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;

    let model = crate::service::find_plugin_model(id, ctx.tenant_id, &state.db).await?;
    let manifest: crate::manifest::PluginManifest =
        serde_json::from_value(model.manifest_json.clone())
            .map_err(|e| AppError::Validation(format!("manifest 解析失败: {}", e)))?;

    let report =
        crate::plugin_validator::validate_plugin_security(&manifest, model.wasm_binary.len())?;
    Ok(Json(ApiResponse::ok(report)))
}
