/**
 * Per-principal access grants for a shared space / project folder.
 *
 *   GET    /api/shared/spaces/[id]/acl?space_type=project   — list grants
 *   PUT    /api/shared/spaces/[id]/acl                       — upsert a grant
 *   DELETE /api/shared/spaces/[id]/acl                       — revoke a grant
 *
 * `[id]` is the LOCAL space id (projects.id or dashboard_spaces.id). The space
 * must already be published to the shared cloud.
 *
 * Auth: requireSession → requireFreshMembership → writer gate (owner|admin|member)
 * for reads. Mutations additionally require org owner/admin OR an 'admin' grant on
 * the space itself (matches the cloud RLS write policy + the space-admin escalation
 * in the permission model).
 */

import { requireSession, requireFreshMembership } from '../../../../../../lib/auth.js';
import {
  isSharedCloudReady,
  grantSpaceAccess,
  revokeSpaceAccess,
  listSpaceAccess,
  resolveSpacePermission,
} from '../../../../../../lib/shared-cloud.js';

export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';

function requireWriter(session) {
  if (!['owner', 'admin', 'member'].includes(session.role)) {
    throw { status: 403, error: 'forbidden' };
  }
}

/** Mutations need org owner/admin, OR an 'admin' grant on this specific space. */
async function requireSpaceAdmin(session, localSpaceId, spaceType) {
  if (['owner', 'admin'].includes(session.role)) return;
  const perm = await resolveSpacePermission({
    local_space_id: localSpaceId,
    user_id: session.user_id,
    space_type: spaceType,
    org_id: session.org_id,
  });
  if (perm === 'admin') return;
  throw { status: 403, error: 'forbidden' };
}

function spaceTypeFromQuery(req) {
  const { searchParams } = new URL(req.url);
  return searchParams.get('space_type') || 'project';
}

function mapError(err, fallbackMsg) {
  if (err && typeof err === 'object' && err.status) {
    return Response.json({ error: err.error || 'unauthorized' }, { status: err.status });
  }
  const msg = String(err?.message || '');
  if (/not configured/i.test(msg)) {
    return Response.json({ error: 'shared_cloud_not_configured' }, { status: 503 });
  }
  if (/not published/i.test(msg)) {
    return Response.json({ error: 'space_not_published' }, { status: 409 });
  }
  if (/invalid (principal_type|permission|space_type)|required/i.test(msg)) {
    return Response.json({ error: msg }, { status: 400 });
  }
  console.error(`${fallbackMsg}:`, err);
  return Response.json({ error: fallbackMsg }, { status: 500 });
}

export async function GET(req, { params }) {
  try {
    const { id } = await params;
    const spaceType = spaceTypeFromQuery(req);
    const session = await requireSession(req);
    await requireFreshMembership(session, session.org_id);
    requireWriter(session);

    const grants = await listSpaceAccess(
      { local_space_id: id, space_type: spaceType, org_id: session.org_id, session },
      {}
    );
    return Response.json({ data: grants });
  } catch (err) {
    return mapError(err, 'Failed to list space access grants');
  }
}

export async function PUT(req, { params }) {
  let body;
  try {
    body = await req.json();
  } catch {
    return Response.json({ error: 'invalid_json' }, { status: 400 });
  }
  try {
    const { id } = await params;
    const spaceType = body?.space_type || spaceTypeFromQuery(req);
    const session = await requireSession(req);
    await requireFreshMembership(session, session.org_id);
    requireWriter(session);
    await requireSpaceAdmin(session, id, spaceType);

    if (!isSharedCloudReady()) {
      return Response.json({ error: 'shared_cloud_not_configured' }, { status: 503 });
    }

    const grant = await grantSpaceAccess(
      {
        local_space_id: id,
        space_type: spaceType,
        principal_type: body?.principal_type,
        principal_id: body?.principal_id,
        permission: body?.permission || 'read',
        session,
      },
      {}
    );
    return Response.json({ data: grant }, { status: 200 });
  } catch (err) {
    return mapError(err, 'Failed to grant space access');
  }
}

export async function DELETE(req, { params }) {
  let body = {};
  try {
    body = await req.json();
  } catch {
    body = {};
  }
  try {
    const { id } = await params;
    const { searchParams } = new URL(req.url);
    const spaceType = body?.space_type || searchParams.get('space_type') || 'project';
    const principal_type = body?.principal_type || searchParams.get('principal_type');
    const principal_id = body?.principal_id || searchParams.get('principal_id');
    const session = await requireSession(req);
    await requireFreshMembership(session, session.org_id);
    requireWriter(session);
    await requireSpaceAdmin(session, id, spaceType);

    if (!isSharedCloudReady()) {
      return Response.json({ error: 'shared_cloud_not_configured' }, { status: 503 });
    }

    const result = await revokeSpaceAccess(
      { local_space_id: id, space_type: spaceType, principal_type, principal_id, session },
      {}
    );
    return Response.json({ data: result }, { status: 200 });
  } catch (err) {
    return mapError(err, 'Failed to revoke space access');
  }
}
