/**
 * @license
 * Copyright (c) 2025 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */

function deepMerge(target, ...sources) {
  const isArray = (item) => Array.isArray(item);
  const isObject = (item) => item && typeof item === 'object' && !isArray(item);
  const merge = (target, source) => {
    if (isObject(source) && isObject(target)) {
      Object.keys(source).forEach((key) => {
        const sourceValue = source[key];
        if (isObject(sourceValue)) {
          if (!target[key]) {
            target[key] = {};
          }
          merge(target[key], sourceValue);
        } else if (isArray(sourceValue)) {
          target[key] = [...sourceValue];
        } else if (sourceValue !== undefined && sourceValue !== null) {
          target[key] = sourceValue;
        }
      });
    }
  };

  sources.forEach((source) => {
    merge(target, source);
  });

  return target;
}

/**
 * A mixin that allows to set partial I18N properties.
 *
 * @polymerMixin
 */
export const I18nMixin = (defaultI18n, superClass) =>
  class I18nMixinClass extends superClass {
    static get properties() {
      return {
        // Even though the property is overridden by a custom getter/setter, it needs to be declared here to initialize
        // __effectiveI18n properly if the i18n property is set before upgrading the element.
        i18n: {
          type: Object,
        },

        /** @private */
        __effectiveI18n: {
          type: Object,
          sync: true,
        },
      };
    }

    constructor() {
      super();

      this.i18n = deepMerge({}, defaultI18n);
    }

    /**
     * The object used to localize this component. To change the default
     * localization, replace this with an object that provides all properties, or
     * just the individual properties you want to change.
     *
     * Should be overridden by subclasses to provide a custom JSDoc with the
     * default I18N properties.
     *
     * @type {Object}
     */
    get i18n() {
      return this.__customI18n;
    }

    set i18n(value) {
      if (value === this.__customI18n) {
        return;
      }
      this.__customI18n = value;
      this.__effectiveI18n = deepMerge({}, defaultI18n, this.__customI18n);
    }
  };
