import { Router } from 'express';
import { canManageSpace } from './visibility.js';
import { viewerOf } from './space-viewer.js';
import type { SpaceApiDeps } from './space-api.js';

/** 公開アプリ共有リンクの発行/失効/取得。createSpaceApi から分離（巨大関数分割）。挙動は等価。 */
export function registerSpaceAppShareRoutes(router: Router, deps: SpaceApiDeps): void {
  const { repo } = deps;

  // ─── 公開アプリ共有リンク（read-only）の発行/失効/取得 ─────────────────
  //
  // スペース内の 1 ワークスペースアプリ（apps/{app}/）を、ログイン不要の公開 URL で
  // read-only 共有するためのトークン管理。発行/失効/取得は canManageSpace（owner /
  // admin / member.role==='owner'）。editor/viewer・非メンバーは触れない。公開側の
  // 配信は app-share-api.ts（認証なし）が担う。shareUrl は相対パス（SPA が origin 前置）。
  // spec: docs/superpowers/specs/2026-06-23-public-app-share-link-design.md

  // app 名はパスセグメント。区切り・親参照を含むものは拒否（apps/{app}/ 解決の安全性）。
  const isSafeAppName = (name: string): boolean =>
    !!name && !name.includes('/') && !name.includes('\\') && !name.includes('..');

  // 現在のリンク状態を取得（canManageSpace）。無ければ { token: null }。
  router.get('/:id/apps/:app/share', async (req, res) => {
    const viewer = viewerOf(req, deps.authActive);
    const space = await repo.getSpace(req.params.id, { viewer });
    if (!space) return res.status(404).json({ error: 'not found' });
    const memberRole = repo.getSpaceMemberRole(space.id, viewer.id);
    if (!canManageSpace(viewer, { ownerId: space.ownerId }, memberRole)) {
      return res.status(403).json({ error: 'forbidden' });
    }
    const appName = req.params.app;
    if (!isSafeAppName(appName)) return res.status(400).json({ error: 'invalid app name' });
    const link = repo.getAppShareLink(space.id, appName);
    if (!link || link.revokedAt) {
      // 失効済みリンクは公開アクセス不可なので token を露出しない（null 扱い）。
      return res.json({ token: null, revokedAt: link?.revokedAt ?? null });
    }
    res.json({ token: link.token, shareUrl: `/ui/app/${link.token}`, revokedAt: link.revokedAt });
  });

  // リンクを発行（canManageSpace）。未失効リンクがあれば再利用。
  router.post('/:id/apps/:app/share', async (req, res) => {
    const viewer = viewerOf(req, deps.authActive);
    const space = await repo.getSpace(req.params.id, { viewer });
    if (!space) return res.status(404).json({ error: 'not found' });
    const memberRole = repo.getSpaceMemberRole(space.id, viewer.id);
    if (!canManageSpace(viewer, { ownerId: space.ownerId }, memberRole)) {
      return res.status(403).json({ error: 'forbidden' });
    }
    const appName = req.params.app;
    if (!isSafeAppName(appName)) return res.status(400).json({ error: 'invalid app name' });
    const createdBy = viewer.id === 'local' ? null : viewer.id;
    const { token } = repo.createAppShareLink(space.id, appName, createdBy);
    res.status(201).json({ token, shareUrl: `/ui/app/${token}` });
  });

  // リンクを失効（canManageSpace）。revoked_at を記録。
  router.delete('/:id/apps/:app/share', async (req, res) => {
    const viewer = viewerOf(req, deps.authActive);
    const space = await repo.getSpace(req.params.id, { viewer });
    if (!space) return res.status(404).json({ error: 'not found' });
    const memberRole = repo.getSpaceMemberRole(space.id, viewer.id);
    if (!canManageSpace(viewer, { ownerId: space.ownerId }, memberRole)) {
      return res.status(403).json({ error: 'forbidden' });
    }
    const appName = req.params.app;
    if (!isSafeAppName(appName)) return res.status(400).json({ error: 'invalid app name' });
    repo.revokeAppShareLink(space.id, appName);
    res.json({ ok: true });
  });
}
