// Copyright 2026 CRMy Contributors
// SPDX-License-Identifier: Apache-2.0

import { OpenApiGeneratorV31 } from '@asteasolutions/zod-to-openapi';
import path from 'node:path';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { registry } from './registry.js';
import './paths.js'; // side-effect: registers all route paths into the registry

const require = createRequire(import.meta.url);
const API_VERSION: string = (() => {
  try {
    const pkg = require(
      path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../package.json'),
    ) as { version?: string };
    return pkg.version ?? 'unknown';
  } catch {
    return 'unknown';
  }
})();

export function buildSpec() {
  const generator = new OpenApiGeneratorV31(registry.definitions);
  // generateDocument does not accept `components` in its config type; merge
  // security schemes into the generated document after the fact.
  const doc = generator.generateDocument({
    openapi: '3.1.0',
    info: {
      title: 'CRMy API',
      version: API_VERSION,
      description:
        'The operational customer context backend for AI agents. MCP-native, PostgreSQL-backed, open source. ' +
        'Application endpoints require `Authorization: Bearer <jwt-or-api-key>` except `/auth/register` and `/auth/login`; provider OAuth callbacks and inbound email webhooks use provider state or tenant-scoped HMAC signatures instead.',
      license: { name: 'Apache-2.0' },
    },
    servers: [
      { url: '/api/v1', description: 'Default (relative to server root)' },
    ],
    tags: [
      { name: 'Auth', description: 'Authentication and API key management' },
      { name: 'Contacts', description: 'Contact records and lifecycle management' },
      { name: 'Accounts', description: 'Account records and hierarchies' },
      { name: 'Opportunities', description: 'Pipeline and deal records' },
      { name: 'Activities', description: 'Logged interactions — calls, emails, meetings, tasks' },
      { name: 'Use Cases', description: 'Consumption-based workload tracking' },
      { name: 'Briefing', description: 'Single-call context assembly before any agent action' },
      { name: 'Context', description: 'Raw Context, Signals, and confirmed Memory attached to customer records' },
      { name: 'Source Filters', description: 'Controls for excluding internal, automated, spam, and low-value source material' },
      { name: 'Assignments', description: 'Structured handoffs between agents and humans' },
      { name: 'HITL', description: 'Human-in-the-loop approval workflows' },
      { name: 'Actors', description: 'First-class identity for humans and AI agents' },
      { name: 'Webhooks', description: 'Outbound event notifications with retry tracking' },
      { name: 'Emails', description: 'Customer email ingestion, mailbox connections, Raw Context processing, and governed outbound drafts' },
      { name: 'Calendar', description: 'Customer meeting capture and activity context processing' },
      { name: 'Messaging', description: 'Tenant messaging channels for workflow and sequence notifications' },
      { name: 'Sequences', description: 'Governed customer engagement sequences and enrollment state' },
      { name: 'Custom Fields', description: 'Per-tenant field definitions for any object type' },
      { name: 'Workflows', description: 'Event-driven automation' },
      { name: 'Systems of Record', description: 'Governed CRM and warehouse connections, sync, conflicts, and writebacks' },
      { name: 'Registries', description: 'Activity type and context type registries' },
      { name: 'Operations', description: 'Tenant operational health, data quality, and recovery controls' },
      { name: 'Admin', description: 'Workspace setup, users, actors, sample data, and local database configuration' },
      { name: 'Analytics', description: 'Pipeline summaries, forecasts, and use case reports' },
      { name: 'Events', description: 'Append-only audit log' },
      { name: 'Search', description: 'Cross-entity full-text search' },
    ],
  });

  // Merge BearerAuth security scheme into the generated components block
  doc.components ??= {};
  doc.components.securitySchemes ??= {};
  doc.components.securitySchemes['BearerAuth'] = {
    type: 'http',
    scheme: 'bearer',
    description: 'JWT from `/auth/login` or a `crmy_` prefixed API key from `/auth/api-keys`',
  };

  return doc;
}

let _cached: ReturnType<typeof buildSpec> | null = null;

/** Returns the OpenAPI document, building it once and caching for the process lifetime. */
export function getSpec(): ReturnType<typeof buildSpec> {
  return (_cached ??= buildSpec());
}
