import { Body, Controller, Get, Post, Req } from "@nestjs/common";
import { IamService } from "./iam.service.js";
import type {
  TokenPair,
  UserInfo,
  ViewportItem,
  ChildInfo,
} from "./iam.service.js";
import {
  registerSchema,
  loginSchema,
  refreshTokenSchema,
  logoutSchema,
} from "./iam.dto.js";
import { UnauthorizedError } from "../shared/errors/application-error.js";
import {
  Permissions,
  RequirePermission,
} from "../middleware/permission.guard.js";
import type { AuthenticatedRequest } from "../middleware/auth.middleware.js";

/**
 * IAM REST Controller（双入口之 REST 侧）。
 *
 * 路径前缀：/v1/iam（I7 裁决：REST 路径统一加 /v1 前缀）
 * gateway 路由：/iam/v1/* → iam /v1/iam/*（透传不改路径）
 *
 * 公开端点：register / login / refresh / jwks（JwksController）
 * 鉴权端点：me / viewports / permissions/effective / children / logout
 */
@Controller("v1/iam")
export class IamController {
  constructor(private readonly service: IamService) {}

  @Post("register")
  async register(
    @Body() body: unknown,
  ): Promise<{ success: true; data: { user: UserInfo; tokens: TokenPair } }> {
    const dto = registerSchema.parse(body);
    const result = await this.service.register(dto);
    return { success: true as const, data: result };
  }

  @Post("login")
  async login(
    @Body() body: unknown,
  ): Promise<{ success: true; data: { user: UserInfo; tokens: TokenPair } }> {
    const dto = loginSchema.parse(body);
    const result = await this.service.login(dto);
    return { success: true as const, data: result };
  }

  @Post("refresh")
  async refresh(
    @Body() body: unknown,
  ): Promise<{ success: true; data: TokenPair }> {
    const dto = refreshTokenSchema.parse(body);
    const tokens = await this.service.refresh(dto.refreshToken);
    return { success: true as const, data: tokens };
  }

  @Post("logout")
  @RequirePermission(Permissions.IAM_USER_READ)
  async logout(
    @Body() body: unknown,
    @Req() req: AuthenticatedRequest,
  ): Promise<{ success: true; data: { success: boolean } }> {
    const dto = logoutSchema.parse(body);
    const userId = req.userId;
    if (!userId) {
      throw new UnauthorizedError("Missing user identity");
    }
    await this.service.logout(dto.refreshToken, userId);
    return { success: true as const, data: { success: true } };
  }

  @Get("me")
  @RequirePermission(Permissions.IAM_USER_READ)
  async me(
    @Req() req: AuthenticatedRequest,
  ): Promise<{ success: true; data: UserInfo }> {
    const userId = req.userId;
    if (!userId) {
      throw new UnauthorizedError("Missing user identity");
    }
    const user = await this.service.getUserInfo(userId);
    return { success: true as const, data: user };
  }

  @Get("viewports")
  @RequirePermission(Permissions.IAM_USER_READ)
  async viewports(
    @Req() req: AuthenticatedRequest,
  ): Promise<{ success: true; data: ViewportItem[] }> {
    const userId = req.userId;
    if (!userId) {
      throw new UnauthorizedError("Missing user identity");
    }
    const data = await this.service.getViewports(userId);
    return { success: true as const, data };
  }

  @Get("permissions/effective")
  @RequirePermission(Permissions.IAM_USER_READ)
  async effectivePermissions(
    @Req() req: AuthenticatedRequest,
  ): Promise<{ success: true; data: { permissions: string[] } }> {
    const userId = req.userId;
    if (!userId) {
      throw new UnauthorizedError("Missing user identity");
    }
    const permissions = await this.service.getEffectivePermissions(userId);
    return { success: true as const, data: { permissions } };
  }

  @Get("children")
  @RequirePermission(Permissions.IAM_USER_READ)
  async children(
    @Req() req: AuthenticatedRequest,
  ): Promise<{ success: true; data: ChildInfo[] }> {
    const userId = req.userId;
    if (!userId) {
      throw new UnauthorizedError("Missing user identity");
    }
    const data = await this.service.getChildrenByParent(userId);
    return { success: true as const, data };
  }
}
