#!/usr/bin/env node
import fs from 'node:fs/promises';
import path from 'node:path';
import { plazaOpenApiExtensions } from './plaza-openapi.mjs';

const OUTPUT_PATH = path.join(import.meta.dirname, '..', 'openapi.json');
const plazaOpenApi = plazaOpenApiExtensions();

const jsonContent = {
  openapi: '3.0.3',
  info: {
    title: 'MindSpace H5 API',
    version: '0.1.0',
    description: 'Generated OpenAPI contract for MindSpace H5, Plaza, and public publication routes.',
  },
  servers: [
    { url: '/api', description: 'Authenticated H5 API' },
    { url: '/', description: 'Public publication and homepage routes' },
  ],
  tags: [
    { name: 'Auth' },
    { name: 'Space' },
    { name: 'Uploads' },
    { name: 'Assets' },
    { name: 'Pages' },
    { name: 'Publications' },
    { name: 'Agent Jobs' },
    { name: 'Public Web' },
    ...plazaOpenApi.tags,
  ],
  paths: {
    '/auth/register': {
      post: {
        tags: ['Auth'],
        summary: 'Register a user and initialize a MindSpace workspace',
        requestBody: {
          required: true,
          content: {
            'application/json': {
              schema: { $ref: '#/components/schemas/RegisterRequest' },
            },
          },
        },
        responses: {
          200: {
            description: 'Registration succeeded',
            content: {
              'application/json': {
                schema: { $ref: '#/components/schemas/RegisterResponseEnvelope' },
              },
            },
          },
        },
      },
    },
    '/auth/login': {
      post: {
        tags: ['Auth'],
        summary: 'Login with username and password',
        requestBody: {
          required: true,
          content: {
            'application/json': {
              schema: { $ref: '#/components/schemas/LoginRequest' },
            },
          },
        },
        responses: {
          200: {
            description: 'Authenticated session',
            content: {
              'application/json': {
                schema: { $ref: '#/components/schemas/AuthStatus' },
              },
            },
          },
        },
      },
    },
    '/auth/logout': {
      post: {
        tags: ['Auth'],
        summary: 'Logout current user session',
        responses: {
          200: {
            description: 'Logged out',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/SuccessEnvelope' } } },
          },
        },
      },
    },
    '/auth/status': {
      get: {
        tags: ['Auth'],
        summary: 'Inspect current auth/session status',
        responses: {
          200: {
            description: 'Current auth status',
            content: {
              'application/json': {
                schema: { $ref: '#/components/schemas/AuthStatus' },
              },
            },
          },
        },
      },
    },
    '/mindspace/v1/space': {
      get: {
        tags: ['Space'],
        summary: 'Get current MindSpace summary, quota, and categories',
        responses: {
          200: {
            description: 'Current space',
            content: {
              'application/json': {
                schema: { $ref: '#/components/schemas/DataEnvelope' },
              },
            },
          },
        },
      },
    },
    '/mindspace/v1/space/quota': {
      get: {
        tags: ['Space'],
        summary: 'Get current quota state',
        responses: {
          200: {
            description: 'Quota state',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/space/categories': {
      get: {
        tags: ['Space'],
        summary: 'List current space categories',
        responses: {
          200: {
            description: 'Category list',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/ListEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/space/cleanup': {
      get: {
        tags: ['Space'],
        summary: 'Preview cleanup candidates',
        responses: {
          200: {
            description: 'Cleanup candidates',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/ListEnvelope' } } },
          },
        },
      },
      post: {
        tags: ['Space'],
        summary: 'Delete selected cleanup candidates',
        requestBody: {
          required: true,
          content: {
            'application/json': {
              schema: { $ref: '#/components/schemas/CleanupRequest' },
            },
          },
        },
        responses: {
          200: {
            description: 'Cleanup result',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/uploads': {
      post: {
        tags: ['Uploads'],
        summary: 'Create an upload session',
        requestBody: {
          required: true,
          content: {
            'application/json': {
              schema: { $ref: '#/components/schemas/CreateUploadRequest' },
            },
          },
        },
        responses: {
          201: {
            description: 'Upload session created',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/uploads/{uploadId}/content': {
      put: {
        tags: ['Uploads'],
        summary: 'Upload raw file bytes',
        parameters: [{ $ref: '#/components/parameters/UploadId' }],
        requestBody: {
          required: true,
          content: {
            'application/octet-stream': {
              schema: { type: 'string', format: 'binary' },
            },
          },
        },
        responses: {
          200: {
            description: 'Bytes written',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/uploads/{uploadId}/complete': {
      post: {
        tags: ['Uploads'],
        summary: 'Complete an upload and materialize the asset',
        parameters: [{ $ref: '#/components/parameters/UploadId' }],
        responses: {
          201: {
            description: 'Asset created',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/uploads/{uploadId}': {
      delete: {
        tags: ['Uploads'],
        summary: 'Cancel upload session',
        parameters: [{ $ref: '#/components/parameters/UploadId' }],
        responses: {
          200: {
            description: 'Upload cancelled',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/assets': {
      get: {
        tags: ['Assets'],
        summary: 'List assets',
        parameters: [
          { name: 'category_id', in: 'query', schema: { type: 'string' } },
          { name: 'category_code', in: 'query', schema: { type: 'string' } },
        ],
        responses: {
          200: {
            description: 'Asset list',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/ListEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/assets/{assetId}/download': {
      get: {
        tags: ['Assets'],
        summary: 'Download asset bytes',
        parameters: [{ $ref: '#/components/parameters/AssetId' }],
        responses: {
          200: {
            description: 'Asset content',
            content: { '*/*': { schema: { type: 'string', format: 'binary' } } },
          },
        },
      },
    },
    '/mindspace/v1/assets/{assetId}/thumbnail': {
      get: {
        tags: ['Assets'],
        summary: 'Render asset thumbnail',
        parameters: [{ $ref: '#/components/parameters/AssetId' }],
        responses: {
          200: {
            description: 'SVG thumbnail',
            content: { 'image/svg+xml': { schema: { type: 'string' } } },
          },
        },
      },
    },
    '/mindspace/v1/assets/{assetId}/preview': {
      get: {
        tags: ['Assets'],
        summary: 'Render asset preview HTML',
        parameters: [{ $ref: '#/components/parameters/AssetId' }],
        responses: {
          200: {
            description: 'Preview HTML',
            content: { 'text/html': { schema: { type: 'string' } } },
          },
        },
      },
    },
    '/mindspace/v1/assets/{assetId}': {
      delete: {
        tags: ['Assets'],
        summary: 'Delete asset',
        parameters: [{ $ref: '#/components/parameters/AssetId' }],
        responses: {
          200: {
            description: 'Delete result',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/analyze-chat-save': {
      post: {
        tags: ['Pages'],
        summary: 'Analyze whether an assistant message should be saved as page or asset',
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/AnalyzeChatSaveRequest' } } },
        },
        responses: {
          200: {
            description: 'Chat save analysis',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/save-from-chat': {
      post: {
        tags: ['Pages'],
        summary: 'Save assistant message into MindSpace',
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/SaveFromChatRequest' } } },
        },
        responses: {
          201: {
            description: 'Saved page or asset',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/from-asset': {
      post: {
        tags: ['Pages'],
        summary: 'Convert an owned asset into a draft page',
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/PageFromAssetRequest' } } },
        },
        responses: {
          201: {
            description: 'Draft page created',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages': {
      get: {
        tags: ['Pages'],
        summary: 'List pages',
        parameters: [{ name: 'status', in: 'query', schema: { type: 'string' } }],
        responses: {
          200: {
            description: 'Page list',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/ListEnvelope' } } },
          },
        },
      },
      post: {
        tags: ['Pages'],
        summary: 'Create a draft page',
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/CreatePageRequest' } } },
        },
        responses: {
          201: {
            description: 'Page created',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/{pageId}': {
      get: {
        tags: ['Pages'],
        summary: 'Get page detail and versions',
        parameters: [{ $ref: '#/components/parameters/PageId' }],
        responses: {
          200: {
            description: 'Page detail',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
      put: {
        tags: ['Pages'],
        summary: 'Create a new page version',
        parameters: [{ $ref: '#/components/parameters/PageId' }],
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/UpdatePageRequest' } } },
        },
        responses: {
          200: {
            description: 'Updated page',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/{pageId}/thumbnail': {
      get: {
        tags: ['Pages'],
        summary: 'Render page thumbnail',
        parameters: [{ $ref: '#/components/parameters/PageId' }],
        responses: {
          200: {
            description: 'SVG thumbnail',
            content: { 'image/svg+xml': { schema: { type: 'string' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/{pageId}/preview': {
      get: {
        tags: ['Pages'],
        summary: 'Render safe page preview HTML',
        parameters: [{ $ref: '#/components/parameters/PageId' }],
        responses: {
          200: {
            description: 'Preview HTML',
            content: { 'text/html': { schema: { type: 'string' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/{pageId}/publish-check': {
      post: {
        tags: ['Publications'],
        summary: 'Check whether page can be published',
        parameters: [{ $ref: '#/components/parameters/PageId' }],
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/PublishCheckRequest' } } },
        },
        responses: {
          200: {
            description: 'Publish check result',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/{pageId}/redacted-copy': {
      post: {
        tags: ['Pages'],
        summary: 'Create a redacted copy of the current page version',
        parameters: [{ $ref: '#/components/parameters/PageId' }],
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/RedactedCopyRequest' } } },
        },
        responses: {
          201: {
            description: 'Redacted page created',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/pages/{pageId}/publish': {
      post: {
        tags: ['Publications'],
        summary: 'Publish the current page version',
        parameters: [{ $ref: '#/components/parameters/PageId' }],
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/PublishPageRequest' } } },
        },
        responses: {
          201: {
            description: 'Publication created',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/publications/{publicationId}/offline': {
      post: {
        tags: ['Publications'],
        summary: 'Offline an online publication',
        parameters: [{ $ref: '#/components/parameters/PublicationId' }],
        responses: {
          200: {
            description: 'Publication offlined',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/publications/{publicationId}/stats': {
      get: {
        tags: ['Publications'],
        summary: 'Get publication statistics',
        parameters: [{ $ref: '#/components/parameters/PublicationId' }],
        responses: {
          200: {
            description: 'Publication stats',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/agent/jobs': {
      get: {
        tags: ['Agent Jobs'],
        summary: 'List current user agent jobs',
        parameters: [{ name: 'limit', in: 'query', schema: { type: 'integer' } }],
        responses: {
          200: {
            description: 'Job list',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/ListEnvelope' } } },
          },
        },
      },
      post: {
        tags: ['Agent Jobs'],
        summary: 'Create an agent job bound to owned assets',
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/CreateAgentJobRequest' } } },
        },
        responses: {
          201: {
            description: 'Job created',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/agent/jobs/{jobId}': {
      get: {
        tags: ['Agent Jobs'],
        summary: 'Get agent job detail',
        parameters: [{ $ref: '#/components/parameters/JobId' }],
        responses: {
          200: {
            description: 'Job detail',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/agent/jobs/{jobId}/cancel': {
      post: {
        tags: ['Agent Jobs'],
        summary: 'Cancel agent job',
        parameters: [{ $ref: '#/components/parameters/JobId' }],
        responses: {
          200: {
            description: 'Cancelled job',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/agent/jobs/{jobId}/retry': {
      post: {
        tags: ['Agent Jobs'],
        summary: 'Retry agent job',
        parameters: [{ $ref: '#/components/parameters/JobId' }],
        responses: {
          200: {
            description: 'Retried job',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/mindspace/v1/agent/jobs/{jobId}/run': {
      post: {
        tags: ['Agent Jobs'],
        summary: 'Start queued agent job execution',
        parameters: [{ $ref: '#/components/parameters/JobId' }],
        responses: {
          202: {
            description: 'Execution started',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/internal/agent/jobs/{jobId}/claim': {
      post: {
        tags: ['Agent Jobs'],
        summary: 'Internal worker claims a queued job',
        parameters: [{ $ref: '#/components/parameters/JobId' }],
        security: [{ bearerAuth: [] }],
        responses: {
          200: {
            description: 'Claimed job payload',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/internal/agent/jobs/{jobId}/assets/{assetId}': {
      get: {
        tags: ['Agent Jobs'],
        summary: 'Internal worker downloads an authorized job asset',
        parameters: [{ $ref: '#/components/parameters/JobId' }, { $ref: '#/components/parameters/AssetId' }],
        security: [{ bearerAuth: [] }],
        responses: {
          200: {
            description: 'Asset content',
            content: { '*/*': { schema: { type: 'string', format: 'binary' } } },
          },
        },
      },
    },
    '/internal/agent/jobs/{jobId}/heartbeat': {
      post: {
        tags: ['Agent Jobs'],
        summary: 'Internal worker posts heartbeat/progress updates',
        parameters: [{ $ref: '#/components/parameters/JobId' }],
        security: [{ bearerAuth: [] }],
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/HeartbeatRequest' } } },
        },
        responses: {
          200: {
            description: 'Progress updated',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/internal/agent/jobs/{jobId}/complete': {
      post: {
        tags: ['Agent Jobs'],
        summary: 'Internal worker completes or fails a job',
        parameters: [{ $ref: '#/components/parameters/JobId' }],
        security: [{ bearerAuth: [] }],
        requestBody: {
          required: true,
          content: { 'application/json': { schema: { $ref: '#/components/schemas/CompleteJobRequest' } } },
        },
        responses: {
          200: {
            description: 'Final job state',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' } } },
          },
        },
      },
    },
    '/u/{ownerSlug}': {
      get: {
        tags: ['Public Web'],
        summary: 'Render public homepage for a user slug',
        parameters: [{ $ref: '#/components/parameters/OwnerSlug' }],
        responses: {
          200: {
            description: 'Public homepage HTML',
            content: { 'text/html': { schema: { type: 'string' } } },
          },
        },
      },
    },
    '/u/{ownerSlug}/pages/{urlSlug}': {
      get: {
        tags: ['Public Web'],
        summary: 'Render a published page via long public route',
        parameters: [{ $ref: '#/components/parameters/OwnerSlug' }, { $ref: '#/components/parameters/UrlSlug' }],
        responses: {
          200: {
            description: 'Published page HTML',
            content: { 'text/html': { schema: { type: 'string' } } },
          },
        },
      },
      post: {
        tags: ['Public Web'],
        summary: 'Submit password gate for a protected page',
        parameters: [{ $ref: '#/components/parameters/OwnerSlug' }, { $ref: '#/components/parameters/UrlSlug' }],
        requestBody: {
          required: true,
          content: {
            'application/x-www-form-urlencoded': {
              schema: {
                type: 'object',
                required: ['password'],
                properties: { password: { type: 'string' } },
              },
            },
          },
        },
        responses: {
          200: {
            description: 'Published page HTML or password gate',
            content: { 'text/html': { schema: { type: 'string' } } },
          },
        },
      },
    },
    '/s/{token}': {
      get: {
        tags: ['Public Web'],
        summary: 'Render a private-link publication',
        parameters: [{ name: 'token', in: 'path', required: true, schema: { type: 'string' } }],
        responses: {
          200: {
            description: 'Published page HTML',
            content: { 'text/html': { schema: { type: 'string' } } },
          },
        },
      },
    },
    ...plazaOpenApi.paths,
  },
  components: {
    securitySchemes: {
      bearerAuth: {
        type: 'http',
        scheme: 'bearer',
      },
    },
    parameters: {
      UploadId: { name: 'uploadId', in: 'path', required: true, schema: { type: 'string' } },
      AssetId: { name: 'assetId', in: 'path', required: true, schema: { type: 'string' } },
      PageId: { name: 'pageId', in: 'path', required: true, schema: { type: 'string' } },
      PublicationId: { name: 'publicationId', in: 'path', required: true, schema: { type: 'string' } },
      JobId: { name: 'jobId', in: 'path', required: true, schema: { type: 'string' } },
      OwnerSlug: { name: 'ownerSlug', in: 'path', required: true, schema: { type: 'string' } },
      UrlSlug: { name: 'urlSlug', in: 'path', required: true, schema: { type: 'string' } },
      ...plazaOpenApi.parameters,
    },
    schemas: {
      SuccessEnvelope: {
        type: 'object',
        properties: {
          ok: { type: 'boolean' },
          request_id: { type: 'string' },
        },
      },
      DataEnvelope: {
        type: 'object',
        required: ['data', 'request_id'],
        properties: {
          data: { type: 'object', additionalProperties: true },
          request_id: { type: 'string' },
        },
      },
      ListEnvelope: {
        type: 'object',
        required: ['data', 'request_id'],
        properties: {
          data: { type: 'array', items: { type: 'object', additionalProperties: true } },
          page: {
            type: 'object',
            properties: {
              next_cursor: { type: ['string', 'null'] },
              has_more: { type: 'boolean' },
            },
          },
          request_id: { type: 'string' },
        },
      },
      AuthStatus: {
        type: 'object',
        additionalProperties: true,
      },
      RegisterRequest: {
        type: 'object',
        required: ['username', 'password', 'displayName', 'email'],
        properties: {
          username: { type: 'string' },
          password: { type: 'string' },
          displayName: { type: 'string' },
          email: { type: 'string' },
        },
      },
      RegisterResponseEnvelope: {
        type: 'object',
        properties: {
          ok: { type: 'boolean' },
          user: { type: 'object', additionalProperties: true },
        },
      },
      LoginRequest: {
        type: 'object',
        required: ['username', 'password'],
        properties: {
          username: { type: 'string' },
          password: { type: 'string' },
        },
      },
      CleanupRequest: {
        type: 'object',
        properties: {
          item_ids: { type: 'array', items: { type: 'string' } },
        },
      },
      CreateUploadRequest: {
        type: 'object',
        required: ['category_id', 'filename', 'size_bytes'],
        properties: {
          category_id: { type: 'string' },
          filename: { type: 'string' },
          size_bytes: { type: 'integer' },
          declared_mime_type: { type: 'string' },
        },
      },
      AnalyzeChatSaveRequest: {
        type: 'object',
        required: ['session_id', 'message_id'],
        properties: {
          session_id: { type: 'string' },
          message_id: { type: 'string' },
          selected_link_index: { type: 'integer' },
        },
      },
      SaveFromChatRequest: {
        type: 'object',
        required: ['session_id', 'message_id'],
        properties: {
          session_id: { type: 'string' },
          message_id: { type: 'string' },
          title: { type: 'string' },
          summary: { type: 'string' },
          template_id: { type: 'string' },
          category_code: { type: 'string' },
          page_type: { type: 'string' },
          selected_link_index: { type: 'integer' },
          acknowledged_finding_ids: { type: 'array', items: { type: 'string' } },
        },
      },
      PageFromAssetRequest: {
        type: 'object',
        required: ['asset_id'],
        properties: {
          asset_id: { type: 'string' },
          title: { type: 'string' },
          summary: { type: 'string' },
          template_id: { type: 'string' },
        },
      },
      CreatePageRequest: {
        type: 'object',
        required: ['title', 'content'],
        properties: {
          title: { type: 'string' },
          summary: { type: 'string' },
          content: { type: 'string' },
          content_format: { type: 'string', enum: ['markdown', 'html'] },
          template_id: { type: 'string' },
          page_type: { type: 'string' },
          category_code: { type: 'string' },
        },
      },
      UpdatePageRequest: {
        type: 'object',
        required: ['expected_version', 'title', 'content'],
        properties: {
          expected_version: { type: 'integer' },
          title: { type: 'string' },
          summary: { type: 'string' },
          content: { type: 'string' },
          template_id: { type: 'string' },
          page_type: { type: 'string' },
          change_note: { type: 'string' },
        },
      },
      PublishCheckRequest: {
        type: 'object',
        required: ['page_version_id', 'access_mode', 'url_slug'],
        properties: {
          page_version_id: { type: 'string' },
          access_mode: { type: 'string' },
          url_slug: { type: 'string' },
          password: { type: 'string' },
          expires_at: { type: 'integer' },
        },
      },
      RedactedCopyRequest: {
        type: 'object',
        properties: {
          page_version_id: { type: 'string' },
        },
      },
      PublishPageRequest: {
        type: 'object',
        required: ['page_version_id', 'access_mode', 'url_slug'],
        properties: {
          page_version_id: { type: 'string' },
          access_mode: { type: 'string' },
          url_slug: { type: 'string' },
          password: { type: 'string' },
          expires_at: { type: 'integer' },
          acknowledged_finding_ids: { type: 'array', items: { type: 'string' } },
        },
      },
      CreateAgentJobRequest: {
        type: 'object',
        required: ['job_type', 'instruction', 'allowed_asset_ids'],
        properties: {
          job_type: { type: 'string' },
          instruction: { type: 'string' },
          allowed_asset_ids: { type: 'array', items: { type: 'string' } },
          output_category_id: { type: 'string' },
          output_type: { type: 'string' },
          idempotency_key: { type: 'string' },
          locale: { type: 'string' },
          timezone: { type: 'string' },
          capabilities: { type: 'object', additionalProperties: { type: 'boolean' } },
        },
      },
      HeartbeatRequest: {
        type: 'object',
        properties: {
          stage: { type: 'string' },
          message: { type: 'string' },
        },
      },
      CompleteJobRequest: {
        type: 'object',
        properties: {
          status: { type: 'string' },
          error_code: { type: 'string' },
          error_message: { type: 'string' },
          output_type: { type: 'string' },
          title: { type: 'string' },
          summary: { type: 'string' },
          content: { type: 'string' },
          content_format: { type: 'string' },
          page_type: { type: 'string' },
          template_id: { type: 'string' },
          source_asset_ids: { type: 'array', items: { type: 'string' } },
        },
      },
      ErrorResponse: {
        type: 'object',
        properties: {
          error: {
            type: 'object',
            properties: {
              code: { type: 'string' },
              message: { type: 'string' },
              details: { type: 'object', additionalProperties: true },
            },
          },
          request_id: { type: 'string' },
        },
      },
      ...plazaOpenApi.schemas,
    },
  },
};

async function main() {
  const rendered = `${JSON.stringify(jsonContent, null, 2)}\n`;
  if (process.argv.includes('--print')) {
    process.stdout.write(rendered);
    return;
  }
  await fs.writeFile(OUTPUT_PATH, rendered);
  process.stdout.write(`Generated ${OUTPUT_PATH}\n`);
}

await main();
