/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: MPL-2.0
 */

import Modifier from 'ember-modifier';
import { assert } from '@ember/debug';

export default class StyleModifier extends Modifier {
  setStyles(newStyles = []) {
    const rulesToRemove = this._oldStyles || new Set();
    if (!Array.isArray(newStyles)) {
      newStyles = Object.entries(newStyles);
    }
    newStyles.forEach(([property, value]) => {
      assert(
        `Your given value for property '${property}' is ${value} (${typeof value}). Accepted types are string and undefined. Please change accordingly.`,
        typeof value === 'undefined' || typeof value === 'string'
      );

      // priority must be specified as separate argument
      // value must not contain "!important"
      let priority = '';
      if (value.length > 0 && value.includes('!important')) {
        priority = 'important';
        value = value.replace('!important', '');
      }

      // update CSSOM
      this.element.style.setProperty(property, value, priority);

      // should not remove rules that have been updated in this cycle
      rulesToRemove.delete(property);
    });

    // remove rules that were present in last cycle but aren't present in this one
    rulesToRemove.forEach((rule) => this.element.style.removeProperty(rule));

    // cache styles that in this rendering cycle for the next one
    this._oldStyles = new Set(newStyles.map((e) => e[0]));
  }

  didReceiveArguments() {
    if (typeof this.args.named.delay !== 'undefined') {
      setTimeout((_) => {
        if (typeof this !== this.args.positional[0]) {
          this.setStyles(this.args.positional[0]);
        }
      }, this.args.named.delay);
    } else {
      this.setStyles(this.args.positional[0]);
    }
  }
}
