use axum::Extension;
use axum::extract::{FromRef, Path, Query, State};
use axum::response::Json;
use serde::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
use validator::Validate;

use erp_core::error::AppError;
use erp_core::types::{ApiResponse, PaginatedResponse, Pagination, TenantContext};
use uuid::Uuid;

use crate::auth_state::AuthState;
use crate::dto::{CreateUserReq, ResetPasswordReq, RoleResp, UpdateUserReq, UserResp};
use crate::service::user_service::UserService;
use erp_core::rbac::require_permission;

/// Query parameters for user list endpoint.
#[derive(Debug, Deserialize, IntoParams)]
pub struct UserListParams {
    pub page: Option<u64>,
    pub page_size: Option<u64>,
    /// Optional search term — filters by username (case-insensitive contains).
    pub search: Option<String>,
}

#[utoipa::path(
    get,
    path = "/api/v1/users",
    params(UserListParams),
    responses(
        (status = 200, description = "成功", body = ApiResponse<PaginatedResponse<UserResp>>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
    ),
    security(("bearer_auth" = [])),
    tag = "用户管理"
)]
/// GET /api/v1/users
///
/// List users within the current tenant with pagination and optional search.
/// Requires the `user.list` permission.
pub async fn list_users<S>(
    State(state): State<AuthState>,
    Extension(ctx): Extension<TenantContext>,
    Query(params): Query<UserListParams>,
) -> Result<Json<ApiResponse<PaginatedResponse<UserResp>>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "user.list")?;

    let pagination = Pagination {
        page: params.page,
        page_size: params.page_size,
    };
    let (users, total) = UserService::list(
        ctx.tenant_id,
        &pagination,
        params.search.as_deref(),
        &state.db,
    )
    .await?;

    let page = pagination.page.unwrap_or(1);
    let page_size = pagination.limit();
    let total_pages = total.div_ceil(page_size);

    Ok(Json(ApiResponse::ok(PaginatedResponse {
        data: users,
        total,
        page,
        page_size,
        total_pages,
    })))
}

#[utoipa::path(
    post,
    path = "/api/v1/users",
    request_body = CreateUserReq,
    responses(
        (status = 200, description = "创建成功", body = ApiResponse<UserResp>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
    ),
    security(("bearer_auth" = [])),
    tag = "用户管理"
)]
/// POST /api/v1/users
///
/// Create a new user within the current tenant.
/// Requires the `user.create` permission.
pub async fn create_user<S>(
    State(state): State<AuthState>,
    Extension(ctx): Extension<TenantContext>,
    Json(mut req): Json<CreateUserReq>,
) -> Result<Json<ApiResponse<UserResp>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "user.create")?;

    req.validate()
        .map_err(|e| AppError::Validation(e.to_string()))?;

    req.sanitize();

    let user = UserService::create(
        ctx.tenant_id,
        ctx.user_id,
        &req,
        &state.db,
        &state.event_bus,
    )
    .await?;

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

#[utoipa::path(
    get,
    path = "/api/v1/users/{id}",
    params(("id" = Uuid, Path, description = "用户ID")),
    responses(
        (status = 200, description = "成功", body = ApiResponse<UserResp>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
        (status = 404, description = "用户不存在"),
    ),
    security(("bearer_auth" = [])),
    tag = "用户管理"
)]
/// GET /api/v1/users/:id
///
/// Fetch a single user by ID within the current tenant.
/// Requires the `user.read` permission.
pub async fn get_user<S>(
    State(state): State<AuthState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<UserResp>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "user.read")?;

    let user = UserService::get_by_id(id, ctx.tenant_id, &state.db).await?;
    Ok(Json(ApiResponse::ok(user)))
}

#[utoipa::path(
    put,
    path = "/api/v1/users/{id}",
    params(("id" = Uuid, Path, description = "用户ID")),
    request_body = UpdateUserReq,
    responses(
        (status = 200, description = "更新成功", body = ApiResponse<UserResp>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
        (status = 404, description = "用户不存在"),
    ),
    security(("bearer_auth" = [])),
    tag = "用户管理"
)]
/// PUT /api/v1/users/:id
///
/// Update editable user fields.
/// Requires the `user.update` permission.
pub async fn update_user<S>(
    State(state): State<AuthState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
    Json(mut req): Json<UpdateUserReq>,
) -> Result<Json<ApiResponse<UserResp>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "user.update")?;

    req.sanitize();

    let user = UserService::update(id, ctx.tenant_id, ctx.user_id, &req, &state.db).await?;
    Ok(Json(ApiResponse::ok(user)))
}

#[utoipa::path(
    delete,
    path = "/api/v1/users/{id}",
    params(("id" = Uuid, Path, description = "用户ID")),
    responses(
        (status = 200, description = "用户已删除"),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
        (status = 404, description = "用户不存在"),
    ),
    security(("bearer_auth" = [])),
    tag = "用户管理"
)]
/// DELETE /api/v1/users/:id
///
/// Soft-delete a user by ID within the current tenant.
/// Requires the `user.delete` permission.
pub async fn delete_user<S>(
    State(state): State<AuthState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
) -> Result<Json<ApiResponse<()>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "user.delete")?;

    UserService::delete(id, ctx.tenant_id, ctx.user_id, &state.db, &state.event_bus).await?;

    Ok(Json(ApiResponse {
        success: true,
        data: None,
        message: Some("用户已删除".to_string()),
    }))
}

/// Assign roles request body.
#[derive(Debug, Deserialize, ToSchema)]
pub struct AssignRolesReq {
    pub role_ids: Vec<Uuid>,
}

/// Assign roles response.
#[derive(Debug, Serialize, ToSchema)]
pub struct AssignRolesResp {
    pub roles: Vec<RoleResp>,
}

#[utoipa::path(
    post,
    path = "/api/v1/users/{id}/roles",
    params(("id" = Uuid, Path, description = "用户ID")),
    request_body = AssignRolesReq,
    responses(
        (status = 200, description = "角色分配成功", body = ApiResponse<AssignRolesResp>),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
        (status = 404, description = "用户不存在"),
    ),
    security(("bearer_auth" = [])),
    tag = "用户管理"
)]
/// POST /api/v1/users/:id/roles
///
/// Replace all role assignments for a user within the current tenant.
/// Requires the `user.update` permission.
pub async fn assign_roles<S>(
    State(state): State<AuthState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
    Json(req): Json<AssignRolesReq>,
) -> Result<Json<ApiResponse<AssignRolesResp>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "user.update")?;

    let roles =
        UserService::assign_roles(id, ctx.tenant_id, ctx.user_id, &req.role_ids, &state.db).await?;

    Ok(Json(ApiResponse::ok(AssignRolesResp { roles })))
}

#[utoipa::path(
    post,
    path = "/api/v1/users/{id}/reset-password",
    params(("id" = Uuid, Path, description = "用户ID")),
    request_body = ResetPasswordReq,
    responses(
        (status = 200, description = "密码重置成功"),
        (status = 401, description = "未授权"),
        (status = 403, description = "权限不足"),
        (status = 404, description = "用户不存在"),
    ),
    security(("bearer_auth" = [])),
    tag = "用户管理"
)]
/// POST /api/v1/users/{id}/reset-password
///
/// 管理员重置指定用户密码。需要 `user.reset-password` 权限。
pub async fn reset_password<S>(
    State(state): State<AuthState>,
    Extension(ctx): Extension<TenantContext>,
    Path(id): Path<Uuid>,
    Json(req): Json<ResetPasswordReq>,
) -> Result<Json<ApiResponse<()>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "user.reset-password")?;

    req.validate()
        .map_err(|e| AppError::Validation(e.to_string()))?;

    UserService::reset_password(
        id,
        ctx.tenant_id,
        ctx.user_id,
        &req.new_password,
        req.version,
        &state.db,
    )
    .await?;

    Ok(Json(ApiResponse {
        success: true,
        data: None,
        message: Some("密码重置成功".to_string()),
    }))
}
