//! 用户管理 API
//!
//! 提供用户的 CRUD 操作、密码重置和状态管理：
//! - GET    /api/users            — 用户列表（分页，支持关键字搜索）
//! - POST   /api/users            — 创建用户（手机号+姓名+角色）
//! - PUT    /api/users/:id        — 编辑用户
//! - PUT    /api/users/:id/reset-password — 重置密码
//! - PUT    /api/users/:id/status — 启用/禁用
//! - DELETE /api/users/:id        — 删除用户

use axum::extract::{Path, Query, State};
use axum::Json;
use chrono::NaiveDateTime;
use serde::Deserialize;
use serde_json::{json, Value};

use crate::error::AppError;
use crate::middleware::auth::{self, CurrentUser};
use crate::commands::AppState;
use crate::config::DEFAULT_PASSWORD;

/// 用户列表查询参数
#[derive(Debug, Deserialize)]
pub(crate) struct UserListQuery {
    page: Option<u32>,
    page_size: Option<u32>,
    keyword: Option<String>,
}

/// 用户列表数据库行映射（替代7元素元组，sqlx 不支持超过6元素的元组）
#[derive(Debug, sqlx::FromRow)]
struct UserRow {
    id: i64,
    phone: String,
    name: Option<String>,
    role: i32,
    organization_id: Option<i64>,
    status: i32,
    created_at: NaiveDateTime,
}

/// 创建用户请求体
#[derive(Debug, Deserialize)]
pub(crate) struct CreateUserInput {
    phone: String,
    name: Option<String>,
    role: Option<i32>,
    organization_id: Option<i64>,
    password: Option<String>,
}

/// 编辑用户请求体
#[derive(Debug, Deserialize)]
pub(crate) struct UpdateUserInput {
    name: Option<String>,
    role: Option<i32>,
    organization_id: Option<i64>,
}

/// 重置密码请求体
#[derive(Debug, Deserialize)]
pub(crate) struct ResetPasswordInput {
    password: Option<String>,
}

/// 状态变更请求体
#[derive(Debug, Deserialize)]
pub(crate) struct StatusInput {
    status: i32,
}

// ---------------------------------------------------------------------------
// 辅助函数: 记录操作日志
// ---------------------------------------------------------------------------

/// 记录一条操作日志到 operation_logs 表
async fn log_operation(
    pool: &sqlx::MySqlPool,
    user_id: i64,
    action: &str,
    target_type: &str,
    target_id: Option<i64>,
    detail: &str,
) {
    let result = sqlx::query(
        "INSERT INTO operation_logs (user_id, action, target_type, target_id, detail) VALUES (?, ?, ?, ?, ?)"
    )
    .bind(user_id)
    .bind(action)
    .bind(target_type)
    .bind(target_id)
    .bind(detail)
    .execute(pool)
    .await;

    if let Err(e) = result {
        tracing::error!("记录操作日志失败: {}", e);
    }
}

// ---------------------------------------------------------------------------
// 用户列表
// ---------------------------------------------------------------------------

/// GET /api/users — 用户列表（分页）
///
/// 支持 keyword 搜索（匹配手机号/姓名），page 从 1 开始。
pub async fn list_users(
    user: CurrentUser,
    State(state): State<AppState>,
    Query(query): Query<UserListQuery>,
) -> Result<Json<Value>, AppError> {
    auth::check_permission(&user, "user:view")?;

    let pool = &state.mysql;
    let page = query.page.unwrap_or(1).max(1);
    let page_size = query.page_size.unwrap_or(20).min(100);
    let offset = (page - 1) * page_size;

    let keyword = query.keyword.as_deref().unwrap_or("");

    // 构建查询条件
    let has_keyword = !keyword.is_empty();
    let like_pattern = format!("%{}%", keyword);

    // 组织隔离：总管理员看所有用户，企业管理员只看本组织用户
    let org_filter = if user.role_level >= 2 {
        None // 总管理员不过滤
    } else {
        user.organization_id // 企业管理员按组织过滤，无组织则返回空
    };

    // 无组织关联的非总管理员用户看不到任何人
    if user.role_level < 2 && org_filter.is_none() {
        return Ok(Json(json!({
            "code": 0,
            "data": { "list": [], "total": 0 },
            "message": "ok"
        })));
    }

    // 查询总数
    let total: (i64,) = if has_keyword {
        let mut q = sqlx::query_as(
            r#"SELECT COUNT(*) FROM users WHERE phone LIKE ? OR name LIKE ?"#,
        )
        .bind(&like_pattern)
        .bind(&like_pattern);
        if let Some(org_id) = org_filter {
            q = sqlx::query_as(
                r#"SELECT COUNT(*) FROM users WHERE (phone LIKE ? OR name LIKE ?) AND organization_id = ?"#,
            )
            .bind(&like_pattern)
            .bind(&like_pattern)
            .bind(org_id);
        }
        q.fetch_one(pool).await?
    } else if let Some(org_id) = org_filter {
        sqlx::query_as("SELECT COUNT(*) FROM users WHERE organization_id = ?")
            .bind(org_id)
            .fetch_one(pool)
            .await?
    } else {
        sqlx::query_as("SELECT COUNT(*) FROM users")
            .fetch_one(pool)
            .await?
    };

    // 查询用户列表
    let rows: Vec<UserRow> = if has_keyword {
        let mut q = sqlx::query_as::<_, UserRow>(
            r#"SELECT u.id, u.phone, u.name, u.role, u.organization_id, u.status, u.created_at
               FROM users u
               WHERE u.phone LIKE ? OR u.name LIKE ?
               ORDER BY u.id DESC
               LIMIT ? OFFSET ?"#,
        )
        .bind(&like_pattern)
        .bind(&like_pattern)
        .bind(page_size)
        .bind(offset);
        if let Some(org_id) = org_filter {
            q = sqlx::query_as::<_, UserRow>(
                r#"SELECT u.id, u.phone, u.name, u.role, u.organization_id, u.status, u.created_at
                   FROM users u
                   WHERE (u.phone LIKE ? OR u.name LIKE ?) AND u.organization_id = ?
                   ORDER BY u.id DESC
                   LIMIT ? OFFSET ?"#,
            )
            .bind(&like_pattern)
            .bind(&like_pattern)
            .bind(org_id)
            .bind(page_size)
            .bind(offset);
        }
        q.fetch_all(pool).await?
    } else if let Some(org_id) = org_filter {
        sqlx::query_as::<_, UserRow>(
            r#"SELECT u.id, u.phone, u.name, u.role, u.organization_id, u.status, u.created_at
               FROM users u
               WHERE u.organization_id = ?
               ORDER BY u.id DESC
               LIMIT ? OFFSET ?"#,
        )
        .bind(org_id)
        .bind(page_size)
        .bind(offset)
        .fetch_all(pool)
        .await?
    } else {
        sqlx::query_as::<_, UserRow>(
            r#"SELECT u.id, u.phone, u.name, u.role, u.organization_id, u.status, u.created_at
               FROM users u
               ORDER BY u.id DESC
               LIMIT ? OFFSET ?"#,
        )
        .bind(page_size)
        .bind(offset)
        .fetch_all(pool)
        .await?
    };

    // 收集组织ID并批量查询组织名称
    let org_ids: Vec<i64> = rows.iter().filter_map(|r| r.organization_id).collect();
    let org_names = if org_ids.is_empty() {
        vec![]
    } else {
        // 使用 IN 查询, 构造占位符
        let placeholders: Vec<String> = org_ids.iter().map(|_| "?".to_string()).collect();
        let sql = format!(
            "SELECT id, name FROM organizations WHERE id IN ({})",
            placeholders.join(",")
        );
        let mut q = sqlx::query_as::<_, (i64, String)>(&sql);
        for id in &org_ids {
            q = q.bind(id);
        }
        q.fetch_all(pool).await.unwrap_or_default()
    };
    let org_map: std::collections::HashMap<i64, String> = org_names.into_iter().collect();

    // 构建角色名称映射
    let role_names: [&str; 3] = ["普通用户", "企业管理员", "总管理员"];

    let list: Vec<Value> = rows
        .into_iter()
        .map(|r| {
            let org_name = r.organization_id.and_then(|oid| org_map.get(&oid).cloned());
            json!({
                "id": r.id,
                "phone": r.phone,
                "name": r.name,
                "role": r.role,
                "role_text": role_names.get(r.role as usize).copied().unwrap_or("未知"),
                "organization_id": r.organization_id,
                "organization_name": org_name,
                "status": r.status,
                "created_at": r.created_at.to_string(),
            })
        })
        .collect();

    Ok(Json(json!({
        "code": 0,
        "data": { "list": list, "total": total.0 },
        "message": "ok"
    })))
}

// ---------------------------------------------------------------------------
// 创建用户
// ---------------------------------------------------------------------------

/// POST /api/users — 创建用户
pub async fn create_user(
    current_user: CurrentUser,
    State(state): State<AppState>,
    Json(input): Json<CreateUserInput>,
) -> Result<Json<Value>, AppError> {
    auth::check_permission(&current_user, "user:create")?;

    let pool = &state.mysql;

    // 校验手机号
    let phone = input.phone.trim();
    if phone.len() != 11 || !phone.chars().all(|c| c.is_ascii_digit()) {
        return Err(AppError::BadRequest("手机号必须为11位数字".into()));
    }

    let name = input.name.filter(|s| !s.trim().is_empty()).map(|s| s.trim().to_string());
    let role = input.role.unwrap_or(0);
    if !(0..=2).contains(&role) {
        return Err(AppError::BadRequest("角色值必须为0(普通)/1(企业管理员)/2(总管理员)".into()));
    }

    // 企业管理员必须指定所属组织
    if role == 1 && input.organization_id.is_none() {
        return Err(AppError::BadRequest("企业管理员必须指定所属组织".into()));
    }

    let org_id = input.organization_id;
    // 校验组织存在
    if let Some(oid) = org_id {
        let org_exists: (i64,) = sqlx::query_as(
            "SELECT COUNT(*) FROM organizations WHERE id = ?"
        )
        .bind(oid)
        .fetch_one(pool)
        .await?;
        if org_exists.0 == 0 {
            return Err(AppError::BadRequest(format!("组织 {} 不存在", oid)));
        }
    }

    let plain_password = input.password.filter(|s| !s.is_empty()).unwrap_or_else(|| DEFAULT_PASSWORD.to_string());
    let password = auth::hash_password(&plain_password)?;

    // 检查手机号是否已存在
    let exists: (i64,) = sqlx::query_as(
        "SELECT COUNT(*) FROM users WHERE phone = ?"
    )
    .bind(phone)
    .fetch_one(pool)
    .await?;
    if exists.0 > 0 {
        return Err(AppError::BadRequest(format!("手机号 {} 已存在", phone)));
    }

    let result = sqlx::query(
        "INSERT INTO users (phone, name, password, role, organization_id) VALUES (?, ?, ?, ?, ?)"
    )
    .bind(phone)
    .bind(&name)
    .bind(&password)
    .bind(role)
    .bind(org_id)
    .execute(pool)
    .await?;

    let user_id = result.last_insert_id() as i64;

    // 记录操作日志
    let detail = format!("创建用户: 手机号={}, 角色={}, 姓名={}", phone, role, name.as_deref().unwrap_or("-"));
    log_operation(pool, current_user.user_id, "create", "user", Some(user_id), &detail).await;

    tracing::info!("创建用户 id={} phone={} role={}", user_id, phone, role);

    Ok(Json(json!({
        "code": 0,
        "data": { "id": user_id },
        "message": "创建成功"
    })))
}

// ---------------------------------------------------------------------------
// 编辑用户
// ---------------------------------------------------------------------------

/// PUT /api/users/:id — 编辑用户
pub async fn update_user(
    current_user: CurrentUser,
    State(state): State<AppState>,
    Path(user_id): Path<i64>,
    Json(input): Json<UpdateUserInput>,
) -> Result<Json<Value>, AppError> {
    auth::check_permission(&current_user, "user:edit")?;

    let pool = &state.mysql;

    // 检查用户存在
    let old: Option<(String, Option<String>, i32, Option<i64>)> = sqlx::query_as(
        "SELECT phone, name, role, organization_id FROM users WHERE id = ?"
    )
    .bind(user_id)
    .fetch_optional(pool)
    .await?;
    let (phone, old_name, old_role, old_org_id) = old
        .ok_or_else(|| AppError::NotFound("用户不存在".into()))?;

    let new_name = input.name.filter(|s| !s.trim().is_empty()).map(|s| s.trim().to_string());
    let new_role = input.role.unwrap_or(old_role);
    if !(0..=2).contains(&new_role) {
        return Err(AppError::BadRequest("角色值必须为0(普通)/1(企业管理员)/2(总管理员)".into()));
    }
    let new_org_id = input.organization_id.or(old_org_id);

    // 企业管理员必须指定所属组织
    if new_role == 1 && new_org_id.is_none() {
        return Err(AppError::BadRequest("企业管理员必须指定所属组织".into()));
    }

    // 校验组织存在
    if let Some(oid) = new_org_id
        && Some(oid) != old_org_id {
            let org_exists: (i64,) = sqlx::query_as(
                "SELECT COUNT(*) FROM organizations WHERE id = ?"
            )
            .bind(oid)
            .fetch_one(pool)
            .await?;
            if org_exists.0 == 0 {
                return Err(AppError::BadRequest(format!("组织 {} 不存在", oid)));
            }
        }

    let rows = sqlx::query(
        "UPDATE users SET name = ?, role = ?, organization_id = ? WHERE id = ?"
    )
    .bind(&new_name)
    .bind(new_role)
    .bind(new_org_id)
    .bind(user_id)
    .execute(pool)
    .await?
    .rows_affected();

    if rows == 0 {
        return Err(AppError::NotFound("用户不存在".into()));
    }

    // 记录操作日志
    let detail = format!(
        "编辑用户: 手机号={}, 姓名: {}→{}, 角色: {}→{}",
        phone,
        old_name.as_deref().unwrap_or("-"),
        new_name.as_deref().unwrap_or("-"),
        old_role, new_role
    );
    log_operation(pool, current_user.user_id, "edit", "user", Some(user_id), &detail).await;

    tracing::info!("编辑用户 id={}", user_id);

    Ok(Json(json!({ "code": 0, "data": null, "message": "更新成功" })))
}

// ---------------------------------------------------------------------------
// 重置密码
// ---------------------------------------------------------------------------

/// PUT /api/users/:id/reset-password — 重置密码
pub async fn reset_password(
    current_user: CurrentUser,
    State(state): State<AppState>,
    Path(user_id): Path<i64>,
    Json(input): Json<ResetPasswordInput>,
) -> Result<Json<Value>, AppError> {
    auth::check_permission(&current_user, "user:edit")?;

    let pool = &state.mysql;
    let plain_password = input.password.filter(|s| !s.is_empty()).unwrap_or_else(|| DEFAULT_PASSWORD.to_string());
    let new_password = auth::hash_password(&plain_password)?;

    let rows = sqlx::query("UPDATE users SET password = ? WHERE id = ?")
        .bind(&new_password)
        .bind(user_id)
        .execute(pool)
        .await?
        .rows_affected();

    if rows == 0 {
        return Err(AppError::NotFound("用户不存在".into()));
    }

    // 记录操作日志
    let detail = format!("重置密码: 用户ID={}", user_id);
    log_operation(pool, current_user.user_id, "edit", "user", Some(user_id), &detail).await;

    tracing::info!("重置密码 user_id={}", user_id);

    Ok(Json(json!({ "code": 0, "data": null, "message": "密码重置成功" })))
}

// ---------------------------------------------------------------------------
// 启用/禁用
// ---------------------------------------------------------------------------

/// PUT /api/users/:id/status — 启用/禁用用户
pub async fn set_user_status(
    current_user: CurrentUser,
    State(state): State<AppState>,
    Path(user_id): Path<i64>,
    Json(input): Json<StatusInput>,
) -> Result<Json<Value>, AppError> {
    auth::check_permission(&current_user, "user:edit")?;

    let pool = &state.mysql;

    // 不能禁用自己
    if user_id == current_user.user_id {
        return Err(AppError::BadRequest("不能修改自己的状态".into()));
    }

    if ![0, 1].contains(&input.status) {
        return Err(AppError::BadRequest("状态值必须为0(禁用)或1(启用)".into()));
    }

    let rows = sqlx::query("UPDATE users SET status = ? WHERE id = ?")
        .bind(input.status)
        .bind(user_id)
        .execute(pool)
        .await?
        .rows_affected();

    if rows == 0 {
        return Err(AppError::NotFound("用户不存在".into()));
    }

    let status_text = if input.status == 1 { "启用" } else { "禁用" };

    // 记录操作日志
    let detail = format!("{}用户: 用户ID={}", status_text, user_id);
    log_operation(pool, current_user.user_id, "edit", "user", Some(user_id), &detail).await;

    tracing::info!("{}用户 user_id={}", status_text, user_id);

    Ok(Json(json!({ "code": 0, "data": null, "message": format!("{}成功", status_text) })))
}

// ---------------------------------------------------------------------------
// 删除用户
// ---------------------------------------------------------------------------

/// DELETE /api/users/:id — 删除用户
pub async fn delete_user(
    current_user: CurrentUser,
    State(state): State<AppState>,
    Path(user_id): Path<i64>,
) -> Result<Json<Value>, AppError> {
    auth::check_permission(&current_user, "user:delete")?;

    let pool = &state.mysql;

    // 不能删除自己
    if user_id == current_user.user_id {
        return Err(AppError::BadRequest("不能删除自己的账户".into()));
    }

    // 查询用户信息用于日志
    let user_info: Option<(String,)> = sqlx::query_as(
        "SELECT phone FROM users WHERE id = ?"
    )
    .bind(user_id)
    .fetch_optional(pool)
    .await?;
    let phone = user_info.map(|(p,)| p).unwrap_or_default();

    let rows = sqlx::query("DELETE FROM users WHERE id = ?")
        .bind(user_id)
        .execute(pool)
        .await?
        .rows_affected();

    if rows == 0 {
        return Err(AppError::NotFound("用户不存在".into()));
    }

    // 记录操作日志
    let detail = format!("删除用户: ID={}, 手机号={}", user_id, phone);
    log_operation(pool, current_user.user_id, "delete", "user", Some(user_id), &detail).await;

    tracing::info!("删除用户 id={} phone={}", user_id, phone);

    Ok(Json(json!({ "code": 0, "data": null, "message": "删除成功" })))
}
