import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  ParseUUIDPipe,
  Patch,
  Post,
  Query,
} from '@nestjs/common';
import {
  IsEnum,
  IsOptional,
  IsString,
  IsUUID,
  MaxLength,
  MinLength,
} from 'class-validator';
import { FieldAccess } from '@prisma/client';
import { RequirePermissions } from '@common/decorators/permissions.decorator';
import { CurrentUser } from '@common/decorators/current-user.decorator';
import { Auditable, Sensitive } from '@core/observability/audit/decorators/auditable.decorator';
import { FieldPermissionService } from '@common/services/field-permission.service';

class CreateFieldPermissionDto {
  @IsUUID()
  roleId!: string;

  @IsString()
  @MinLength(1)
  @MaxLength(64)
  resource!: string;

  @IsString()
  @MinLength(1)
  @MaxLength(64)
  field!: string;

  @IsEnum(FieldAccess)
  access!: FieldAccess;
}

class UpdateFieldPermissionDto {
  @IsOptional()
  @IsEnum(FieldAccess)
  access?: FieldAccess;
}

/**
 * IAM 后台：字段级权限 CRUD（规则 §5.4）
 */
@Controller('iam/field-permissions')
export class FieldPermissionsController {
  constructor(private readonly service: FieldPermissionService) {}

  @Get()
  @RequirePermissions('iam_admin:read')
  list(
    @Query('resource') resource?: string,
    @Query('roleId') roleId?: string,
  ) {
    return this.service.adminList({ resource, roleId });
  }

  @Post()
  @RequirePermissions('iam_admin:manage')
  @Auditable()
  @Sensitive()
  create(
    @Body() body: CreateFieldPermissionDto,
    @CurrentUser('userId') actor: string,
  ) {
    return this.service.adminCreate(body, actor);
  }

  @Patch(':id')
  @RequirePermissions('iam_admin:manage')
  @Auditable()
  @Sensitive()
  update(
    @Param('id', ParseUUIDPipe) id: string,
    @Body() body: UpdateFieldPermissionDto,
    @CurrentUser('userId') actor: string,
  ) {
    return this.service.adminUpdate(id, body, actor);
  }

  @Delete(':id')
  @RequirePermissions('iam_admin:manage')
  @Auditable()
  @Sensitive()
  remove(
    @Param('id', ParseUUIDPipe) id: string,
    @CurrentUser('userId') actor: string,
  ) {
    return this.service.adminRemove(id, actor);
  }
}
