use axum::extract::{FromRef, State};
use axum::response::Json;
use validator::Validate;

use erp_core::error::AppError;
use erp_core::types::ApiResponse;

use crate::auth_state::AuthState;
use crate::dto::{LoginResp, WechatBindPhoneReq, WechatLoginReq, WechatLoginResp};
use crate::service::wechat_service::WechatService;

#[utoipa::path(
    post,
    path = "/api/v1/auth/wechat/login",
    request_body = WechatLoginReq,
    responses(
        (status = 200, description = "微信登录成功", body = ApiResponse<WechatLoginResp>),
        (status = 400, description = "请求参数错误"),
    ),
    tag = "认证"
)]
/// POST /api/v1/auth/wechat/login
///
/// 微信小程序登录：用 code 换 openid，查询绑定状态。
/// 已绑定用户直接返回 JWT，未绑定用户返回 openid 供后续绑定。
pub async fn wechat_login<S>(
    State(state): State<AuthState>,
    Json(req): Json<WechatLoginReq>,
) -> Result<Json<ApiResponse<WechatLoginResp>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    req.validate()
        .map_err(|e| AppError::Validation(e.to_string()))?;

    tracing::info!(
        code = %req.code,
        tenant_id = %state.default_tenant_id,
        has_appid = !state.wechat_appid.is_empty(),
        has_secret = !state.wechat_secret.is_empty(),
        "微信登录请求"
    );

    // TODO: 多租户微信登录需要设计租户解析策略（如 per-appid 映射或登录后选择租户）
    let tenant_id = state.default_tenant_id;
    let resp = WechatService::login(&state, tenant_id, &req.code).await?;
    tracing::info!(
        bound = resp.bound,
        has_token = resp.token.is_some(),
        "微信登录结果"
    );
    Ok(Json(ApiResponse::ok(resp)))
}

#[utoipa::path(
    post,
    path = "/api/v1/auth/wechat/bind-phone",
    request_body = WechatBindPhoneReq,
    responses(
        (status = 200, description = "绑定成功", body = ApiResponse<LoginResp>),
        (status = 400, description = "请求参数错误"),
    ),
    tag = "认证"
)]
/// POST /api/v1/auth/wechat/bind-phone
///
/// 微信手机号绑定：解密手机号，创建/关联 user，签发 JWT。
pub async fn wechat_bind_phone<S>(
    State(state): State<AuthState>,
    Json(req): Json<WechatBindPhoneReq>,
) -> Result<Json<ApiResponse<LoginResp>>, AppError>
where
    AuthState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    req.validate()
        .map_err(|e| AppError::Validation(e.to_string()))?;

    // TODO: 多租户微信登录需要设计租户解析策略
    let tenant_id = state.default_tenant_id;
    let resp =
        WechatService::bind_phone(&state, tenant_id, &req.openid, &req.encrypted_data, &req.iv)
            .await?;
    Ok(Json(ApiResponse::ok(resp)))
}
