// lib/tools/adapters/composite-definitions.js
//
// Adapters for `create_composite_tool` / `update_composite_tool`. Both call the
// composite sole-writer (upsertCompositeTool). The strict composite spec-validator
// is the authority on shape; approval/role gates fire in executeRegistryTool BEFORE
// these run. Mirrors the workflow-definitions precedent.
//
// Provenance (agent_id / acting user) is threaded into created_by_* columns.
// Primitive-tool metadata (known names + per-tool risk) is read from the registry
// and handed to the validator so a recipe can only reference real, gated tools and
// inherit their risk correctly.

import { getDb } from '../../db.js';
import { upsertCompositeTool, getCompositeTool, archiveCompositeTool } from '../composite/registry.js';
import { listPrimitiveToolMeta } from '../registry.js';

function asActingUserId(options) {
  return options?.acting_on_behalf_of_user_id || options?.user_id || null;
}

function hasAuthoringAuthority(options = {}) {
  if (options.owner_trusted) return true;
  if (options.actor_role === 'owner' || options.actor_role === 'admin') return true;
  const userId = asActingUserId(options);
  if (!userId || userId === 'system') return false;
  try {
    const row = getDb()
      .prepare("SELECT role FROM org_memberships WHERE user_id=? AND org_id=COALESCE(?, 'personal-org')")
      .get(userId, options.org_id || 'personal-org');
    return row?.role === 'owner' || row?.role === 'admin';
  } catch {
    return false;
  }
}

function insufficientRole() {
  return {
    ok: false,
    status: 'error',
    error: 'insufficient_role',
    message: 'Composite tool authoring requires owner/admin authority in addition to tool approval.',
  };
}

function structuredErrorFromUpsert(err) {
  if (err?.code === 'spec_invalid') {
    return { ok: false, status: 'error', error: 'spec_invalid', errors: err.errors || [err.message] };
  }
  return null;
}

export async function createCompositeTool(input, options = {}) {
  if (!hasAuthoringAuthority(options)) return insufficientRole();
  const spec = input?.spec;
  if (!spec || typeof spec !== 'object') {
    return { ok: false, status: 'error', error: 'spec_required', message: 'spec required (object)' };
  }
  if (!spec.slug || typeof spec.slug !== 'string') {
    return { ok: false, error: 'slug_required', message: 'spec.slug required (string)' };
  }
  if (getCompositeTool(spec.slug)) {
    return { ok: false, status: 'error', error: 'slug_in_use', slug: spec.slug };
  }
  const meta = listPrimitiveToolMeta();
  // A composite slug must not shadow an existing primitive/connector tool name.
  if (meta.names.has(spec.slug)) {
    return { ok: false, status: 'error', error: 'slug_in_use', slug: spec.slug, message: 'slug collides with an existing tool' };
  }
  try {
    const r = upsertCompositeTool(
      spec,
      { created_by_user_id: asActingUserId(options), created_by_agent_id: options?.agent_id || null },
      { knownToolNames: meta.names, toolRiskByName: meta.riskByName },
    );
    return { ok: true, status: 'complete', slug: r.slug, risk_level: r.risk_level, warnings: r.warnings || [] };
  } catch (err) {
    const structured = structuredErrorFromUpsert(err);
    if (structured) return structured;
    throw err;
  }
}

export async function updateCompositeTool(input, options = {}) {
  if (!hasAuthoringAuthority(options)) return insufficientRole();
  const slug = typeof input?.slug === 'string' ? input.slug.trim() : '';
  const spec = input?.spec;
  if (!slug) return { ok: false, status: 'error', error: 'slug_required', message: 'slug required (string)' };
  if (!spec || typeof spec !== 'object') {
    return { ok: false, status: 'error', error: 'spec_required', message: 'spec required (object)' };
  }
  if (!getCompositeTool(slug)) return { ok: false, status: 'error', error: 'not_found', slug };
  const meta = listPrimitiveToolMeta();
  const cloned = { ...spec, slug };
  try {
    const r = upsertCompositeTool(
      cloned,
      { created_by_user_id: asActingUserId(options), created_by_agent_id: options?.agent_id || null },
      { knownToolNames: meta.names, toolRiskByName: meta.riskByName },
    );
    return { ok: true, status: 'complete', slug: r.slug, risk_level: r.risk_level, warnings: r.warnings || [] };
  } catch (err) {
    const structured = structuredErrorFromUpsert(err);
    if (structured) return structured;
    throw err;
  }
}

export { archiveCompositeTool };
