// #region builder:plugin-imports
import { createClient } from './client.js';
import { createToolkit, type Toolkit } from './toolkit.js';
// #endregion
import type { PluginContext } from './types.js';

// #region builder:plugin-module-imports
// LLM-authored slot. Add module-top imports the activate-body needs that
// the auto-managed slots don't cover — e.g. `import express from 'express'`,
// `import path from 'node:path'`, `import { fileURLToPath } from 'node:url'`
// for the admin-UI mount described in CLAUDE.md. Third-party imports must
// be backed by an entry in package.json#peerDependencies (express + zod +
// @omadia/plugin-ui-helpers ship by default). Empty by default.
// #endregion

// #region builder:external-reads-imports
// Auto-generated by codegen from spec.external_reads — do not edit by hand.
// Codegen splices `import { z } from 'zod';` and `import type { … } from
// '@omadia/integration-…'` lines here when the spec carries
// external_reads entries. Empty by default.
// #endregion

// #region builder:ui-routes-imports
// Auto-generated by codegen from spec.ui_routes — do not edit by hand.
// Codegen splices Router imports + per-route UiRouter factory imports
// here when the spec carries ui_routes entries. Empty by default.
// #endregion

export const AGENT_ID = '{{AGENT_ID}}' as const;

/**
 * Runtime contract (harness platform v1):
 *   - activate(ctx) has a 10s budget (self-test: 1 GET, no full crawl).
 *   - close()       has a 5s budget — REALLY release timers/connections/watches.
 *   - Return shape is fixed: { toolkit, close() }. LocalSubAgent, tool bridge,
 *     DomainTool wrap, tool-name derivation, systemPrompt concat are handled
 *     by the runtime. No own LLM client here.
 */
export interface AgentHandle {
  readonly toolkit: Toolkit;
  close(): Promise<void>;
}

export async function activate(ctx: PluginContext): Promise<AgentHandle> {
  ctx.log('activating');

  // #region builder:activate-body
  // Secrets: resolved along the depends_on chain. `require` throws when missing.
  const apiToken = await ctx.secrets.require('API_TOKEN');

  // Config: non-secret setup.fields. `get<T>` for optional + default, `require<T>` for mandatory.
  const baseUrl = ctx.config.require<string>('base_url');
  const timeoutMs = ctx.config.get<number>('request_timeout_ms') ?? 15_000;

  const client = createClient({
    baseUrl,
    token: apiToken,
    timeoutMs,
    log: ctx.log,
  });

  // Self-Test: leichtgewichtig, ein GET. NICHT Vollcrawl / Bulk-Sync.
  await client.ping();
  ctx.log('self-test ok', { baseUrl });

  const toolkit = createToolkit({
    client,
    log: ctx.log,
  });
  // #endregion

  // #region builder:external-reads-init
  // Auto-generated from spec.external_reads — do not edit by hand. Codegen
  // synthesises typed `ctx.services.get(...)` lookups + tool descriptors
  // here from the declarative spec.external_reads[] entries; the LLM does
  // NOT fill this slot. Empty by default — the marker stays in place even
  // when the spec has no external reads.
  // #endregion

  const __uiRouteDisposers: Array<() => void> = [];
  // #region builder:ui-routes-init
  // Auto-generated from spec.ui_routes — do not edit by hand. Codegen
  // synthesises per-route Express routers, `ctx.routes.register(...)`
  // mounts, and `ctx.uiRoutes.register(...)` descriptor wiring here.
  // The disposer-array above collects every register() return value so
  // close() can tear down everything cleanly. Empty by default.
  // #endregion

  return {
    toolkit,
    async close() {
      ctx.log('deactivating');
      // B.12 — tear down every ui_route mount + descriptor. The loop is
      // always present (no-op when ui_routes is empty); the disposers are
      // pushed by the codegen-managed ui-routes-init region above.
      for (const dispose of __uiRouteDisposers) {
        try {
          dispose();
        } catch (err) {
          ctx.log('ui-route dispose failed', err);
        }
      }
      await toolkit.close();
    },
  };
}

export default { AGENT_ID, activate };
