use axum::{
    extract::{Path, State},
    response::IntoResponse,
};
use interim_models::workspace_user_perm::{self, WorkspaceUserPerm};
use interim_pgtypes::escape_identifier;
use serde::Deserialize;
use sqlx::query;
use uuid::Uuid;

use crate::{
    app::AppDbConn,
    errors::{AppError, forbidden},
    navigator::Navigator,
    settings::Settings,
    user::CurrentUser,
    workspace_pooler::{RoleAssignment, WorkspacePooler},
};

#[derive(Debug, Deserialize)]
pub(super) struct PathParams {
    workspace_id: Uuid,
}

/// HTTP POST handler for creating a managed Postgres table within a workspace
/// database. Upon success, it redirects the client back to the workspace
/// homepage, which is expected to display a list of available tables including
/// the newly created one.
///
/// This handler expects 1 path parameter named `workspace_id` which should
/// deserialize to a UUID.
pub(super) async fn post(
    State(settings): State<Settings>,
    State(mut pooler): State<WorkspacePooler>,
    CurrentUser(user): CurrentUser,
    navigator: Navigator,
    AppDbConn(mut app_db): AppDbConn,
    Path(PathParams { workspace_id }): Path<PathParams>,
) -> Result<impl IntoResponse, AppError> {
    // Check workspace authorization.
    let workspace_perms = WorkspaceUserPerm::belonging_to_user(user.id)
        .fetch_all(&mut app_db)
        .await?;
    if workspace_perms.iter().all(|p| {
        p.workspace_id != workspace_id || p.perm != workspace_user_perm::PermissionValue::Connect
    }) {
        return Err(forbidden!("access denied to workspace"));
    }

    let mut workspace_client = pooler
        // FIXME: Should this be scoped down to the unprivileged role after
        // setting up the table owner?
        .acquire_for(workspace_id, RoleAssignment::Root)
        .await?;

    let table_owner_rolname = format!("table_owner_{0}", Uuid::new_v4().simple());
    query(&format!(
        "create role {0}",
        escape_identifier(&table_owner_rolname),
    ))
    .execute(workspace_client.get_conn())
    .await?;
    query(&format!(
        "grant {0} to {1} with admin option",
        escape_identifier(&table_owner_rolname),
        escape_identifier(&format!(
            "{0}{1}",
            settings.db_role_prefix,
            user.id.simple()
        ))
    ))
    .execute(workspace_client.get_conn())
    .await?;
    query(&format!(
        "grant create, usage on schema {0} to {1}",
        escape_identifier(&settings.phono_table_namespace),
        escape_identifier(&table_owner_rolname),
    ))
    .execute(workspace_client.get_conn())
    .await?;
    const TABLE_NAME: &str = "untitled";
    query(&format!(
        r#"
create table {0}.{1} (
    _id uuid primary key not null default uuidv7(),
    _created_by text default current_user,
    _created_at timestamptz not null default now(),
    _form_session uuid,
    _form_backlink_portal uuid,
    _form_backlink_row uuid,
    notes text
)
"#,
        escape_identifier(&settings.phono_table_namespace),
        escape_identifier(TABLE_NAME),
    ))
    .execute(workspace_client.get_conn())
    .await?;
    query(&format!(
        "alter table {0}.{1} owner to {2}",
        escape_identifier(&settings.phono_table_namespace),
        escape_identifier(TABLE_NAME),
        escape_identifier(&table_owner_rolname)
    ))
    .execute(workspace_client.get_conn())
    .await?;

    Ok(navigator.workspace_page(workspace_id).redirect_to())
}
