import express from 'express';
import { readFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { Repository } from '../db/repository.js';
import { logger } from '../logger.js';
import { loadConfig } from '../config.js';
import { requireAdmin, DEFAULT_SESSION_SECRET_PATH } from './auth.js';
import { registerShutdownHook } from './shutdown.js';
import { createA2aOidcProvider, mountA2aOidc } from './a2a/oidc-provider.js';
import { createA2aClientsAdminRouter } from './a2a/a2a-clients-admin-api.js';
import { createA2aRouter, createSpaceA2aAdminRouter } from './a2a/a2a-api.js';
import { mountA2aRequestHandler } from './a2a/request-handler.js';
import { A2aTaskReconciler } from './a2a/reconciler.js';
import { createUserDelegationsRouter, createAdminDelegationsRouter } from './a2a/delegations-api.js';

/**
 * A2A OAuth2 Authorization Server + Agent Card + JSON-RPC + admin routers,
 * extracted verbatim from createCoreServer (bridge/server.ts). No-op unless
 * `a2a.enabled: true` in config.yaml. Registration order relative to the
 * other /api/local mounts is preserved by the call site in server.ts.
 */
export function setupA2aSubsystem(
  app: express.Express,
  deps: { repo: Repository; authActive: boolean },
): void {
  const { repo, authActive } = deps;

  // --- A2A OAuth2 Authorization Server ---
  const a2aCfg = (loadConfig() as any).a2a ?? {};
  if (a2aCfg.enabled) {
    if (!authActive) {
      logger.warn('[a2a-oidc] a2a.enabled but auth is not active; consent flow requires login and will reject all requests');
    }
    try {
      const sessionSecretPath = loadConfig()?.secrets?.sessionSecretPath ?? DEFAULT_SESSION_SECRET_PATH;
      const cookieKeys = [readFileSync(sessionSecretPath, 'utf-8').trim()];
      const secretsDir = dirname(resolve(sessionSecretPath));
      const provider = createA2aOidcProvider({
        repo,
        secretsDir,
        issuer: a2aCfg.issuer,
        resourceAudience: a2aCfg.resourceAudience,
        cookieKeys,
      });
      mountA2aOidc(app, provider, { repo, resourceAudience: a2aCfg.resourceAudience });
      app.use('/api/admin/a2a/clients', express.json(), requireAdmin, createA2aClientsAdminRouter(repo, authActive));
      // Agent Card ルータ (base card = public, extended card = self-authenticates via Bearer)
      // baseUrl は resourceAudience の origin から導く（例: https://maestro.example.com/a2a → https://maestro.example.com）
      // version は '1.0.0' 固定（生成済みバージョンファイルが存在しないため定数を使用）
      const a2aBaseUrl = (() => {
        try { return new URL(String(a2aCfg.resourceAudience)).origin; } catch { return String(a2aCfg.issuer); }
      })();
      app.use(createA2aRouter({ provider, repo, baseUrl: a2aBaseUrl, issuer: String(a2aCfg.issuer), version: '1.0.0' }));
      // JSON-RPC エンドポイント /a2a（SDK DefaultRequestHandler 経由）
      // /a2a は /api 配下でないため requireAuth に掛からない。認証は UserBuilder が担う。
      mountA2aRequestHandler(app, { provider, repo, baseUrl: a2aBaseUrl, issuer: String(a2aCfg.issuer), version: '1.0.0', limits: a2aCfg.limits });
      // bridge は単一プロセス前提。複数プロセスが同一 DB を共有する構成では
      // lease が必要になる（将来課題）。
      const a2aReconciler = new A2aTaskReconciler({ repo });
      a2aReconciler.start();
      registerShutdownHook('a2a-reconciler', async () => { a2aReconciler.stop(); });
      logger.info('[a2a] task reconciler started');
      // スペース A2A スキル許可リスト管理 API (/api/local は requireAuth 配下)
      app.use('/api/local/spaces', createSpaceA2aAdminRouter(repo, authActive));
      // A2A 委任一覧・取消 API
      // /api/local は server.ts 側で requireAuth 済みのため追加ゲート不要
      app.use('/api/local/a2a/delegations', express.json(), createUserDelegationsRouter(repo, authActive));
      app.use('/api/admin/a2a/delegations', express.json(), requireAdmin, createAdminDelegationsRouter(repo, authActive));
      logger.info('[a2a-oidc] a2a authorization server enabled');
    } catch (err) {
      logger.warn(`[a2a-oidc] failed to mount a2a authorization server: ${err}`);
    }
  }
}
