import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  ParseUUIDPipe,
  Patch,
  Post,
  Query,
} from '@nestjs/common';
import {
  IsEnum,
  IsObject,
  IsOptional,
  IsString,
  Matches,
  MaxLength,
  MinLength,
} from 'class-validator';
import { DataScopeType, Prisma } 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 { DataScopeAdminService } from './data-scope-admin.service';

class CreateDataScopeDto {
  @IsString()
  @MinLength(2)
  @MaxLength(64)
  @Matches(/^[A-Z0-9_]+$/, {
    message: 'code 必须是大写字母/数字/下划线',
  })
  code!: string;

  @IsString()
  @MinLength(2)
  @MaxLength(128)
  name!: string;

  @IsEnum(DataScopeType)
  scopeType!: DataScopeType;

  @IsOptional()
  @IsObject()
  rules?: Record<string, unknown>;
}

class UpdateDataScopeDto {
  @IsOptional()
  @IsString()
  @MinLength(2)
  @MaxLength(128)
  name?: string;

  @IsOptional()
  @IsEnum(DataScopeType)
  scopeType?: DataScopeType;

  @IsOptional()
  @IsObject()
  rules?: Record<string, unknown> | null;
}

/**
 * IAM 后台：DataScope 定义 CRUD（规则 §5.3）
 *
 * 鉴权：iam_admin:read（GET）/ iam_admin:manage（写）；Administrator auto-bypass。
 */
@Controller('iam/data-scopes')
export class DataScopesController {
  constructor(private readonly service: DataScopeAdminService) {}

  @Get()
  @RequirePermissions('iam_admin:read')
  list() {
    return this.service.list();
  }

  @Get('by-role')
  @RequirePermissions('iam_admin:read')
  listByRole(@Query('roleId', ParseUUIDPipe) roleId: string) {
    return this.service.listByRole(roleId);
  }

  @Post()
  @RequirePermissions('iam_admin:manage')
  @Auditable()
  @Sensitive()
  create(@Body() body: CreateDataScopeDto, @CurrentUser('userId') actor: string) {
    return this.service.create(
      {
        code: body.code,
        name: body.name,
        scopeType: body.scopeType,
        rules: (body.rules ?? null) as Prisma.InputJsonValue | null,
      },
      actor,
    );
  }

  @Patch(':id')
  @RequirePermissions('iam_admin:manage')
  @Auditable()
  @Sensitive()
  update(
    @Param('id', ParseUUIDPipe) id: string,
    @Body() body: UpdateDataScopeDto,
    @CurrentUser('userId') actor: string,
  ) {
    return this.service.update(
      id,
      {
        name: body.name,
        scopeType: body.scopeType,
        rules: body.rules as Prisma.InputJsonValue | null | undefined,
      },
      actor,
    );
  }

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