import '../debug/index.js';
import { E as ENV } from '../../shared-chunks/env-DxZ20QzS.js';
import { s as setClassicDecorator, i as isElementDescriptor, e as expandProperties } from '../../shared-chunks/cache-DtDz7X5V.js';
export { c as computed, d as defineProperty, g as get, n as notifyPropertyChange } from '../../shared-chunks/cache-DtDz7X5V.js';
import '../-internals/meta/lib/meta.js';
import '../../@glimmer/validator/index.js';
import { s as setObservers } from '../../shared-chunks/mandatory-setter-CXNsxygN.js';
import { isDevelopingApp } from '@embroider/macros';
import '../../@glimmer/destroyable/index.js';
import '../../@glimmer/manager/index.js';
export { s as set, t as trySet } from '../../shared-chunks/property_set-n9lAuzYY.js';
export { g as getProperties, s as setProperties } from '../../shared-chunks/set_properties-D2_u0phU.js';
import { g as getFactoryFor } from '../../shared-chunks/registry-BJpQx6hv.js';
import CoreObject from './core.js';
import Observable from './observable.js';
import { assert } from '../debug/lib/assert.js';

/**
@module @ember/object
*/

/**
  `EmberObject` is the main base class for all Ember objects. It is a subclass
  of `CoreObject` with the `Observable` mixin applied. For details,
  see the documentation for each of these.

  @class EmberObject
  @extends CoreObject
  @uses Observable
  @public
*/
// eslint-disable-next-line @typescript-eslint/no-empty-object-type

class EmberObject extends CoreObject.extend(Observable) {
  get _debugContainerKey() {
    let factory = getFactoryFor(this);
    return factory !== undefined && factory.fullName;
  }
}

/**
  Decorator that turns the target function into an Action which can be accessed
  directly by reference.

  ```js
  import Component from '@ember/component';
  import { tracked } from '@glimmer/tracking';
  import { action } from '@ember/object';

  export default class Tooltip extends Component {
    @tracked isShowing = false;

    @action
    toggleShowing() {
      this.isShowing = !this.isShowing;
    }
  }
  ```
  ```hbs
  <!-- template.hbs -->
  <button {{on "click" this.toggleShowing}}>Show tooltip</button>

  {{#if isShowing}}
    <div class="tooltip">
      I'm a tooltip!
    </div>
  {{/if}}
  ```

  It also binds the function directly to the instance, so it can be used in any
  context and will correctly refer to the class it came from:

  ```js
  import Component from '@ember/component';
  import { tracked } from '@glimmer/tracking';
  import { action } from '@ember/object';

  export default class Tooltip extends Component {
    constructor() {
      super(...arguments);

      // this.toggleShowing is still bound correctly when added to
      // the event listener
      document.addEventListener('click', this.toggleShowing);
    }

    @tracked isShowing = false;

    @action
    toggleShowing() {
      this.isShowing = !this.isShowing;
    }
  }
  ```

  @public
  @method action
  @for @ember/object
  @static
  @param {Function|undefined} callback The function to turn into an action,
                                       when used in classic classes
  @return {PropertyDecorator} property decorator instance
*/

const BINDINGS_MAP = new WeakMap();
function hasProto(obj) {
  return obj != null && obj.constructor !== undefined && typeof obj.constructor.proto === 'function';
}
function setupAction(target, key, actionFn) {
  if (hasProto(target)) {
    target.constructor.proto();
  }
  if (!Object.prototype.hasOwnProperty.call(target, 'actions')) {
    let parentActions = target.actions;
    // we need to assign because of the way mixins copy actions down when inheriting
    target.actions = parentActions ? Object.assign({}, parentActions) : {};
  }
  (isDevelopingApp() && !(target.actions != null) && assert("[BUG] Somehow the target doesn't have actions!", target.actions != null));
  target.actions[key] = actionFn;
  return {
    get() {
      let bindings = BINDINGS_MAP.get(this);
      if (bindings === undefined) {
        bindings = new Map();
        BINDINGS_MAP.set(this, bindings);
      }
      let fn = bindings.get(actionFn);
      if (fn === undefined) {
        fn = actionFn.bind(this);
        bindings.set(actionFn, fn);
      }
      return fn;
    }
  };
}
function action(...args) {
  let actionFn;
  if (!isElementDescriptor(args)) {
    actionFn = args[0];
    let decorator = function (target, key, _desc, _meta, isClassicDecorator) {
      (isDevelopingApp() && !(isClassicDecorator) && assert('The @action decorator may only be passed a method when used in classic classes. You should decorate methods directly in native classes', isClassicDecorator));
      (isDevelopingApp() && !(typeof actionFn === 'function') && assert('The action() decorator must be passed a method when used in classic classes', typeof actionFn === 'function'));
      return setupAction(target, key, actionFn);
    };
    setClassicDecorator(decorator);
    return decorator;
  }
  let [target, key, desc] = args;
  actionFn = desc?.value;
  (isDevelopingApp() && !(typeof actionFn === 'function') && assert('The @action decorator must be applied to methods when used in native classes', typeof actionFn === 'function')); // SAFETY: TS types are weird with decorators. This should work.
  return setupAction(target, key, actionFn);
}

// SAFETY: TS types are weird with decorators. This should work.
setClassicDecorator(action);

// ..........................................................
// OBSERVER HELPER
//

/**
  Specify a method that observes property changes.

  ```javascript
  import EmberObject from '@ember/object';
  import { observer } from '@ember/object';

  export default EmberObject.extend({
    valueObserver: observer('value', function() {
      // Executes whenever the "value" property changes
    })
  });
  ```

  Also available as `Function.prototype.observes` if prototype extensions are
  enabled.

  @method observer
  @for @ember/object
  @param {String} propertyNames*
  @param {Function} func
  @return func
  @public
  @static
*/
function observer(...args) {
  let funcOrDef = args.pop();
  (isDevelopingApp() && !(typeof funcOrDef === 'function' || typeof funcOrDef === 'object' && funcOrDef !== null) && assert('observer must be provided a function or an observer definition', typeof funcOrDef === 'function' || typeof funcOrDef === 'object' && funcOrDef !== null));
  let func;
  let dependentKeys;
  let sync;
  if (typeof funcOrDef === 'function') {
    func = funcOrDef;
    dependentKeys = args;
    sync = !ENV._DEFAULT_ASYNC_OBSERVERS;
  } else {
    func = funcOrDef.fn;
    dependentKeys = funcOrDef.dependentKeys;
    sync = funcOrDef.sync;
  }
  (isDevelopingApp() && !(typeof func === 'function') && assert('observer called without a function', typeof func === 'function'));
  (isDevelopingApp() && !(Array.isArray(dependentKeys) && dependentKeys.length > 0 && dependentKeys.every(p => typeof p === 'string' && Boolean(p.length))) && assert('observer called without valid path', Array.isArray(dependentKeys) && dependentKeys.length > 0 && dependentKeys.every(p => typeof p === 'string' && Boolean(p.length))));
  (isDevelopingApp() && !(typeof sync === 'boolean') && assert('observer called without sync', typeof sync === 'boolean'));
  let paths = [];
  for (let dependentKey of dependentKeys) {
    expandProperties(dependentKey, path => paths.push(path));
  }
  setObservers(func, {
    paths,
    sync
  });
  return func;
}

export { action, EmberObject as default, observer };
