import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import type { AccessTokenPayload } from '@pac/types';
import { ROLE_PERMISSIONS } from '@pac/types';
import type { TenantScopeContext } from '../../common/decorators/tenant-scope.decorator';
import { OrgTreeService } from '../auth/org-tree';

export interface McpAuthContext {
  scope: TenantScopeContext;
  permissions: string[];
}

/**
 * McpAuthService — MCP 端点的 Bearer 鉴权。
 *
 * 复用平台 JWT(AuthModule 配置的 jwt.secret)。token payload 带 hostId/tenantId/orgScope/permissions,
 * → 派生 TenantScopeContext,每个工具调用据此**强制租户隔离**(与 REST 同一套边界)。
 */
@Injectable()
export class McpAuthService {
  constructor(
    private readonly jwt: JwtService,
    private readonly orgTree: OrgTreeService,
  ) {}

  async verifyBearer(authHeader: string | undefined): Promise<McpAuthContext> {
    if (!authHeader?.startsWith('Bearer ')) {
      throw new UnauthorizedException('缺 Bearer token');
    }
    const token = authHeader.slice('Bearer '.length).trim();
    let payload: AccessTokenPayload;
    try {
      payload = await this.jwt.verifyAsync<AccessTokenPayload>(token);
    } catch {
      throw new UnauthorizedException('token 无效或已过期');
    }
    if (!payload?.hostId || !payload?.tenantId) {
      throw new UnauthorizedException('token payload 缺 host/tenant');
    }
    // 设计 B:JWT 装通用 orgScope,这里展开成内部过滤维(与 REST 拦截器同一套,树从摄入数据派生)。
    const { sourceUnits, clinicIds } = await this.orgTree.expandScope(
      payload.hostId,
      payload.tenantId,
      payload.orgScope ?? [],
    );
    return {
      scope: {
        hostId: payload.hostId,
        tenantId: payload.tenantId,
        clinicIds,
        sourceUnits,
        userId: payload.sub,
      },
      // ⭐ 按 role 现算,与 PermissionsGuard / GET /auth/session 同源(见 permissions.guard 长注释)。
      //   MCP 这条路尤其要现算:工具清单是按能力**条件注册**的,权限少一个 = 助手手里少几个工具,
      //   模型只会说"我没有这个能力",既不报错也看不出是 token 过期。
      permissions: ROLE_PERMISSIONS[payload.role] ?? payload.permissions ?? [],
    };
  }
}
