import { AccessRule, AccessRuleSchema } from '../rules/AccessRule.js'
import { RateLimitingConfiguration, RateLimitingConfigurationSchema } from '../rules/RateLimitingConfiguration.js'
import { observed } from '../../decorators/observed.js'
import { restoreAccessRule } from '../rules/index.js'

/**
 * A base interface for common properties across all actions.
 */
export interface ActionSchema {
  /**
   * The specific kind of action (e.g., 'List', 'Read', etc.)
   */
  kind: string
  /**
   * Access control rules defining who can perform this action. It is only applied if the
   * authorization strategy is set to 'RBAC'.
   * If no rules grant access, it's denied by default making it essentially private.
   *
   * Note, the API can defined top level access rules that apply to all actions. If this property is set,
   * it overrides the top level access rules for this specific action.
   *
   * It is an ordered list, meaning the first rule that matches the user will be applied.
   * If multiple rules match, the first one in the list takes precedence.
   * If no rules match, the action is denied.
   */
  accessRule?: AccessRuleSchema[]
  /**
   * Optional configuration for action-wide rate limiting and throttling.
   * Defines rules to protect the action from overuse.
   */
  rateLimiting?: RateLimitingConfigurationSchema
}

/**
 * A base class for common properties across all actions.
 */
export class Action extends EventTarget implements ActionSchema {
  @observed() accessor kind: string
  @observed({ deep: true }) accessor accessRule: AccessRule[]
  @observed({ deep: true }) accessor rateLimiting: RateLimitingConfiguration | undefined

  constructor(state: Partial<ActionSchema> = {}) {
    super()
    this.kind = state.kind || ''
    this.accessRule = state.accessRule ? state.accessRule.map((rule) => restoreAccessRule(rule)) : []
    this.rateLimiting = state.rateLimiting ? new RateLimitingConfiguration(state.rateLimiting) : undefined
  }

  notifyChange() {
    this.dispatchEvent(new Event('change'))
  }

  toJSON(): ActionSchema {
    const result: ActionSchema = {
      kind: this.kind,
    }
    if (this.accessRule.length) {
      result.accessRule = this.accessRule.map((rule) => rule.toJSON())
    }
    if (this.rateLimiting) {
      result.rateLimiting = this.rateLimiting.toJSON()
    }
    return result
  }
}
