/**
 * delegations-api.ts — A2A 委任の一覧・取消ルーター
 *
 * createUserDelegationsRouter: /api/local/a2a/delegations  (requireAuth 配下)
 * createAdminDelegationsRouter: /api/admin/a2a/delegations (requireAdmin 配下)
 */
import { Router, type Request, type Response } from 'express';
import type { Repository } from '../../db/repository.js';
import { logger } from '../../logger.js';
import { viewerOf } from '../space-viewer.js';
import { revokeDelegationCascade } from './revoke.js';
import { isDelegationLive } from './delegation.js';

// ── User router ───────────────────────────────────────────────────────────────

/**
 * ログイン中ユーザー自身の委任一覧と取消。
 * /api/local は server.ts で requireAuth 済みのため追加ゲート不要。
 */
export function createUserDelegationsRouter(repo: Repository, authActive: boolean): Router {
  const router = Router();

  // GET / — viewer の委任一覧
  router.get('/', (req: Request, res: Response) => {
    try {
      const viewer = viewerOf(req, authActive);
      const nowIso = new Date().toISOString();
      const rows = repo.listA2aDelegationsForUserWithClient(viewer.id);
      const delegations = rows.map(d => ({
        id: d.id,
        clientId: d.clientId,
        clientName: d.clientName,
        grantedSpaceIds: d.grantedSpaceIds,
        grantedSkills: d.grantedSkills,
        expiresAt: d.expiresAt ?? null,
        revokedAt: d.revokedAt ?? null,
        createdAt: d.createdAt ?? null,
        live: isDelegationLive(d, nowIso),
      }));
      logger.info(`[a2a-api] listDelegations userId=${viewer.id} count=${delegations.length}`);
      res.json({ delegations });
    } catch (err) {
      logger.error(`[a2a-api] listDelegations failed: ${err}`);
      res.status(500).json({ error: 'internal' });
    }
  });

  // POST /:id/revoke — viewer 自身の委任を取消
  // not-found と forbidden は両方 404 で返す（存在リーク防止）
  router.post('/:id/revoke', async (req: Request, res: Response) => {
    try {
      const viewer = viewerOf(req, authActive);
      const nowIso = new Date().toISOString();
      const outcome = await revokeDelegationCascade(
        repo,
        req.params.id,
        { userId: viewer.id, isAdmin: false },
        nowIso,
      );
      if (outcome.status === 'revoked' || outcome.status === 'already-revoked') {
        logger.info(
          `[a2a-api] revoke delegationId=${req.params.id} status=${outcome.status} userId=${viewer.id}`,
        );
        const body: Record<string, unknown> = { status: outcome.status };
        if ('cancelledJobs' in outcome) body.cancelledJobs = outcome.cancelledJobs;
        res.json(body);
      } else {
        // 'not-found' | 'forbidden' → 同一 404（存在リーク防止）
        logger.info(
          `[a2a-api] revoke delegationId=${req.params.id} outcome=${outcome.status} userId=${viewer.id} → 404`,
        );
        res.status(404).json({ error: 'not_found' });
      }
    } catch (err) {
      logger.error(`[a2a-api] revoke failed delegationId=${req.params.id}: ${err}`);
      res.status(500).json({ error: 'internal' });
    }
  });

  return router;
}

// ── Admin router ──────────────────────────────────────────────────────────────

/**
 * 管理者向け全委任一覧と取消。
 * server.ts で requireAdmin が前段に置かれる前提。
 */
export function createAdminDelegationsRouter(repo: Repository, authActive: boolean): Router {
  const router = Router();

  // GET / — 全ユーザーの委任一覧
  router.get('/', (_req: Request, res: Response) => {
    try {
      const nowIso = new Date().toISOString();
      const rows = repo.listA2aDelegationsAllWithClient();
      const delegations = rows.map(d => ({
        id: d.id,
        userId: d.userId,
        clientId: d.clientId,
        clientName: d.clientName,
        grantedSpaceIds: d.grantedSpaceIds,
        grantedSkills: d.grantedSkills,
        expiresAt: d.expiresAt ?? null,
        revokedAt: d.revokedAt ?? null,
        createdAt: d.createdAt ?? null,
        live: isDelegationLive(d, nowIso),
      }));
      logger.info(`[a2a-api] adminListDelegations count=${delegations.length}`);
      res.json({ delegations });
    } catch (err) {
      logger.error(`[a2a-api] adminListDelegations failed: ${err}`);
      res.status(500).json({ error: 'internal' });
    }
  });

  // POST /:id/revoke — 管理者が任意ユーザーの委任を取消
  // revoked/already-revoked → 200；not-found → 404；その他 → 500（防衛的）
  router.post('/:id/revoke', async (req: Request, res: Response) => {
    try {
      const admin = viewerOf(req, authActive);
      const nowIso = new Date().toISOString();
      const outcome = await revokeDelegationCascade(
        repo,
        req.params.id,
        { userId: admin.id, isAdmin: true },
        nowIso,
      );
      if (outcome.status === 'revoked' || outcome.status === 'already-revoked') {
        logger.info(
          `[a2a-api] adminRevoke delegationId=${req.params.id} status=${outcome.status} adminId=${admin.id}`,
        );
        const body: Record<string, unknown> = { status: outcome.status };
        if ('cancelledJobs' in outcome) body.cancelledJobs = outcome.cancelledJobs;
        res.json(body);
      } else if (outcome.status === 'not-found') {
        res.status(404).json({ error: 'not_found' });
      } else {
        // defensive: 'forbidden' or any future unknown status → 500
        logger.error(`[a2a-api] adminRevoke unexpected status=${outcome.status} delegationId=${req.params.id}`);
        res.status(500).json({ error: 'internal' });
      }
    } catch (err) {
      logger.error(`[a2a-api] adminRevoke failed delegationId=${req.params.id}: ${err}`);
      res.status(500).json({ error: 'internal' });
    }
  });

  return router;
}
