import { BadRequestException, ForbiddenException, UnauthorizedException } from '@nestjs/common';
import type { Request as ExpressRequest } from 'express';

/**
 * AgentModule 控制器统一的 actor / org 解析。
 *
 * 兜底优先级：
 *   1. 显式参数（query / body）
 *   2. X-Organization-Id header（前端 OrganizationContext 切组织时由 api-client 注入）
 *   3. JWT actor.currentOrganizationId
 *   4. organizationRoles 第一个 key
 */

export interface AgentActor {
  userId?: string;
  id?: string;
  email?: string;
  organizationRoles?: Record<string, string[]>;
  currentOrganizationId?: string;
  permissions?: string[];
}

export function getActor(req: ExpressRequest): AgentActor | undefined {
  return req.user as AgentActor | undefined;
}

function actorBelongsToOrg(actor: AgentActor | undefined, orgId: string): boolean {
  if (!actor) return false;
  if (actor.currentOrganizationId === orgId) return true;
  return Object.prototype.hasOwnProperty.call(actor.organizationRoles ?? {}, orgId);
}

export function resolveOrgId(req: ExpressRequest, explicit?: string): string | null {
  const actor = getActor(req);
  // body / query 显式传 orgId 时必须校验 actor 归属，否则跨 org 写入向量成立（INV-1）
  if (explicit) {
    if (!actorBelongsToOrg(actor, explicit)) {
      throw new ForbiddenException(`actor not in organization ${explicit}`);
    }
    return explicit;
  }
  const headerOrg = req.headers['x-organization-id'];
  const fromHeader = Array.isArray(headerOrg) ? headerOrg[0] : headerOrg;
  if (fromHeader) {
    if (!actorBelongsToOrg(actor, fromHeader)) {
      throw new ForbiddenException(`actor not in organization ${fromHeader}`);
    }
    return fromHeader;
  }
  if (actor?.currentOrganizationId) return actor.currentOrganizationId;
  const keys = actor?.organizationRoles ? Object.keys(actor.organizationRoles) : [];
  return keys[0] ?? null;
}

/**
 * 一次性拿到 actor + orgId + userId 用于业务逻辑；缺则抛对应 HTTP 异常。
 */
export function resolveActor(
  req: ExpressRequest,
  explicitOrg?: string,
): { actor: AgentActor; orgId: string; userId: string } {
  const actor = getActor(req);
  const userId = actor?.userId ?? actor?.id;
  if (!userId) throw new UnauthorizedException();
  const orgId = resolveOrgId(req, explicitOrg);
  if (!orgId) throw new BadRequestException('organizationId required');
  return { actor: actor!, orgId, userId };
}
