use axum::{
    Extension, Json,
    extract::{Path, State},
    http::StatusCode,
};
use serde::Deserialize;
use serde_json::{Value, json};

use crate::{
    auth::AuthenticatedSession,
    error::ApiError,
    service::{InvitationPayload, UpdateMembershipPayload},
    state::AppState,
};

#[derive(Deserialize)]
pub struct WorkspacePath {
    pub workspace_id: String,
}

#[derive(Deserialize)]
pub struct WorkspaceInvitationPath {
    pub workspace_id: String,
    pub invitation_id: String,
}

#[derive(Deserialize)]
pub struct WorkspaceMembershipPath {
    pub workspace_id: String,
    pub user_id: String,
}

pub async fn list_memberships(
    Path(path): Path<WorkspacePath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let items = state
        .service
        .list_memberships(&path.workspace_id.as_str().into())
        .await?;
    Ok(Json(json!({ "items": items })))
}

pub async fn update_membership(
    Path(path): Path<WorkspaceMembershipPath>,
    State(state): State<AppState>,
    Extension(session): Extension<AuthenticatedSession>,
    Json(payload): Json<UpdateMembershipPayload>,
) -> Result<Json<Value>, ApiError> {
    let items = state
        .service
        .update_membership_role(
            &path.workspace_id.as_str().into(),
            &session.user.id,
            &path.user_id.as_str().into(),
            payload,
        )
        .await?;
    Ok(Json(json!({ "items": items })))
}

pub async fn delete_membership(
    Path(path): Path<WorkspaceMembershipPath>,
    State(state): State<AppState>,
    Extension(session): Extension<AuthenticatedSession>,
) -> Result<StatusCode, ApiError> {
    state
        .service
        .remove_membership(
            &path.workspace_id.as_str().into(),
            &session.user.id,
            &path.user_id.as_str().into(),
        )
        .await?;
    Ok(StatusCode::NO_CONTENT)
}

pub async fn list_invitations(
    Path(path): Path<WorkspacePath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let items = state
        .service
        .list_invitations(&path.workspace_id.as_str().into())
        .await?;
    Ok(Json(json!({ "items": items })))
}

pub async fn create_invitation(
    Path(path): Path<WorkspacePath>,
    State(state): State<AppState>,
    Json(payload): Json<InvitationPayload>,
) -> Result<Json<Value>, ApiError> {
    let created = state
        .service
        .create_invitation(&path.workspace_id.as_str().into(), payload)
        .await?;
    Ok(Json(json!(created)))
}

pub async fn delete_invitation(
    Path(path): Path<WorkspaceInvitationPath>,
    State(state): State<AppState>,
) -> Result<StatusCode, ApiError> {
    state
        .service
        .delete_invitation(
            &path.workspace_id.as_str().into(),
            &path.invitation_id.as_str().into(),
        )
        .await?;
    Ok(StatusCode::NO_CONTENT)
}

pub async fn export_workspace(
    Path(path): Path<WorkspacePath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let exported = state
        .service
        .export_workspace(&path.workspace_id.as_str().into())
        .await?;
    Ok(Json(json!(exported)))
}

pub async fn delete_workspace(
    Path(path): Path<WorkspacePath>,
    State(state): State<AppState>,
    Extension(session): Extension<AuthenticatedSession>,
) -> Result<StatusCode, ApiError> {
    state
        .service
        .delete_workspace(&path.workspace_id.as_str().into(), &session.user.id)
        .await?;
    Ok(StatusCode::NO_CONTENT)
}
