import { IsIn, IsISO8601, IsOptional, IsString, MaxLength } from 'class-validator';
import { SCOPE_KINDS, type ScopeKind } from 'shared-auth';

/**
 * Payload accepted by `POST /api/admin/users/:oid/scopes`. Kind is
 * validated against the closed catalogue; value validation against
 * `Structure.code` / `Delegation.code` / `Region.code` (ADR-0027 PR 1)
 * happens server-side in `UserScopesService.grant`. v1 has no
 * partial-update; a re-grant with a different `expiresAt` requires
 * delete + add.
 */
export class GrantUserScopeDto {
  @IsString()
  @IsIn(SCOPE_KINDS as ReadonlyArray<string>)
  kind!: ScopeKind;

  /**
   * Value tied to `kind`. Required and non-empty for value-bearing
   * kinds (`etablissement` / `delegation` / `region`); must be empty
   * (or omitted — coerced to '' in the service) for valueless kinds
   * (`self` / `siege` / `unrestricted`). The shape match is handled
   * by `UserScopesService.grant` so the error surface is one place.
   */
  @IsString()
  @MaxLength(64)
  @IsOptional()
  value?: string;

  /**
   * Optional ISO-8601 expiry. When set and past, `PrismaScopeResolver`
   * filters the row out at sign-in (`expiresAt IS NULL OR > NOW()`)
   * per ADR-0026 PR 2a — supports interim-director-for-two-months
   * patterns without a row deletion.
   */
  @IsISO8601()
  @IsOptional()
  expiresAt?: string;
}

/**
 * Single row in `GET /api/admin/users/:oid/scopes`. Mirrors
 * `UserScope` columns; timestamps as ISO strings so the SPA never
 * has to round-trip `Date` instances.
 */
export interface UserScopeDto {
  readonly id: string;
  readonly kind: string;
  readonly value: string;
  readonly source: string;
  readonly createdAt: string;
  readonly expiresAt: string | null;
}

/**
 * Response of `GET /api/admin/users/:oid/scopes`. Includes a
 * `user` envelope so the SPA can confirm the right target user
 * without a second round-trip; `displayName` + `email` are pulled
 * from the linked `Person` row.
 */
export interface UserScopesPageDto {
  readonly user: {
    readonly oid: string;
    readonly userId: string;
    readonly displayName: string;
    readonly email: string | null;
  };
  readonly scopes: ReadonlyArray<UserScopeDto>;
}
