import { AccessRule, type AccessRuleSchema } from './AccessRule.js'
import { observed } from '../../decorators/observed.js'

/**
 * The action is allowed if the authenticated user's ID matches a specific property on the resource.
 * This is typically used to restrict access to resources owned by the user.
 * For example, a user can only access their own profile or documents.
 */
export interface MatchResourceOwnerAccessRuleSchema extends AccessRuleSchema {
  type: 'matchResourceOwner'
  /**
   * The property on the resource that references the user's ID (the key in the semantically annotated `User` entity).
   *
   * When the current exposed entity has a property annotated with the "ResourceOwnerIdentifier" semantic,
   * this property should be used. It directly references the user's key.
   *
   * The domain model should annotate this property with the "ResourceOwnerIdentifier" semantic
   * to indicate that it is used for ownership checks.
   */
  property?: string

  /**
   * The target for the ownership check.
   * - `property`: The check is performed against a specific property on the resource (default).
   * - `user-entity`: The check is performed against the entity itself (used when the entity represents the user).
   */
  target?: 'property' | 'user-entity'
}

/**
 * The action is allowed if the authenticated user's ID matches a specific property on the resource.
 * This is typically used to restrict access to resources owned by the user.
 * For example, a user can only access their own profile or documents.
 */
export class MatchResourceOwnerAccessRule extends AccessRule implements MatchResourceOwnerAccessRuleSchema {
  override readonly type: 'matchResourceOwner'

  @observed() accessor property: string | undefined
  @observed() accessor target: 'property' | 'user-entity'

  constructor(state: Partial<MatchResourceOwnerAccessRuleSchema> = {}) {
    super(state)
    this.type = 'matchResourceOwner'
    this.property = state.property
    this.target = state.target ?? 'property'
  }

  override toJSON(): MatchResourceOwnerAccessRuleSchema {
    const json: MatchResourceOwnerAccessRuleSchema = {
      ...(super.toJSON() as MatchResourceOwnerAccessRuleSchema),
      target: this.target,
    }
    if (this.property) {
      json.property = this.property
    }
    return json
  }
}
