import type { UserInfoDto, ChildDto, ViewportDto } from "./dtos.js";
import { callWithMetrics } from "./grpc/call-with-metrics.js";
import { MOCK_PARENT, MOCK_CHILDREN, MOCK_VIEWPORTS } from "./mock-data.js";

/**
 * IAM 下游客户端接口（对齐 02-architecture-design.md §7.1 交互矩阵）。
 *
 * 方法：
 * - getUserInfo: IamService.GetUserInfo（✅ 已有）
 * - getChildrenByParent: IamService.GetChildrenByParent（❌ 待 ai06 补，I6 裁决 P0）
 * - getViewports: IamService.GetViewports（❌ 待 ai06 补）
 * - getEffectivePermissions: IamService.GetEffectivePermissions（❌ 待 ai06 补）
 */
export interface IamClient {
  getUserInfo(userId: string): Promise<UserInfoDto>;
  getChildrenByParent(parentId: string): Promise<ChildDto[]>;
  getViewports(userId: string): Promise<ViewportDto[]>;
  getEffectivePermissions(userId: string): Promise<string[]>;
}

/**
 * Mock IAM 客户端（DEV_MODE=true 时使用）。
 *
 * 返回固定数据：parent-001 王家长 + 2 个孩子（student-001 + student-002）。
 */
export class MockIamClient implements IamClient {
  async getUserInfo(userId: string): Promise<UserInfoDto> {
    if (userId !== MOCK_PARENT.id) {
      return { ...MOCK_PARENT, id: userId, name: "测试家长" };
    }
    return { ...MOCK_PARENT };
  }

  async getChildrenByParent(_parentId: string): Promise<ChildDto[]> {
    // 关键约束：返回的 student_id 必须与 core-edu mock 一致
    return MOCK_CHILDREN.map((c) => ({ ...c }));
  }

  async getViewports(_userId: string): Promise<ViewportDto[]> {
    return MOCK_VIEWPORTS.map((v) => ({ ...v }));
  }

  async getEffectivePermissions(userId: string): Promise<string[]> {
    if (userId !== MOCK_PARENT.id) {
      return ["parent:dashboard:view"];
    }
    return [...MOCK_PARENT.permissions];
  }
}

/**
 * gRPC IAM 客户端。
 *
 * 通过 proto-loader 动态加载 iam.proto，调用 IamService RPCs。
 *
 * 注意：GetChildrenByParent / GetViewports / GetEffectivePermissions
 * 尚未在 proto 中定义（待 ai06 补），上游补全后 proto-loader 自动识别。
 */
export class GrpcIamClient implements IamClient {
  private readonly rawClient: unknown;

  constructor(rawClient: unknown) {
    this.rawClient = rawClient;
  }

  async getUserInfo(userId: string): Promise<UserInfoDto> {
    return callWithMetrics<{ userId: string }, UserInfoDto>(
      this.rawClient,
      "getUserInfo",
      { userId },
      "iam",
    );
  }

  async getChildrenByParent(parentId: string): Promise<ChildDto[]> {
    const res = await callWithMetrics<
      { parentId: string },
      { children: ChildDto[] }
    >(this.rawClient, "getChildrenByParent", { parentId }, "iam");
    return res.children ?? [];
  }

  async getViewports(userId: string): Promise<ViewportDto[]> {
    const res = await callWithMetrics<
      { userId: string },
      { viewports: ViewportDto[] }
    >(this.rawClient, "getViewports", { userId }, "iam");
    return res.viewports ?? [];
  }

  async getEffectivePermissions(userId: string): Promise<string[]> {
    const res = await callWithMetrics<
      { userId: string },
      { permissions: string[] }
    >(this.rawClient, "getEffectivePermissions", { userId }, "iam");
    return res.permissions ?? [];
  }
}
