/*-
 * ~~~~~~licensing~~~~~~
 * entaxy-management-plugin
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
var Entaxy;
(function (Entaxy) {
    Entaxy._module.component('entaxyMapInput', {
        bindings: {
            model: '=',
            items: '=',
            duplicateKeys: '=',
            hasErrors: '=',
            readonly: '<',
            setFocused: '<',
            formController: '<'
        },
        template:
        `
          <div class="entaxy-map-input-table" ng-if="$ctrl.items && $ctrl.items.length > 0">
            <table>
              <tbody>
                <tr role="row" ng-repeat="field in $ctrl.items">
                  <td class="input-cell">
                    <input type="text" class="form-control" ng-model="field.key" ng-change="$ctrl.changeKey(field)"
                            ng-class="{'has-error': field.hasError}" ng-readonly="$ctrl.readonly || field.removed"/>
                  </td>
                  <td class="input-cell">
                    <input type="text" class="form-control" ng-model="field.value" ng-change="$ctrl.changeValue(field)"
                            ng-readonly="$ctrl.readonly || field.removed"/>
                  </td>
                  <td ng-if="!$ctrl.readonly">
                    <button type="button" class="btn-std btn-std-ignore-error" ng-click="$ctrl.remove(field)"
                            data-toggle="tooltip" title="Remove" ng-if="!field.removed">
                      <span class="pficon pficon-delete"></span>
                    </button>
                    <button type="button" class="btn-std btn-std-ignore-error" ng-click="$ctrl.restore(field)"
                            data-toggle="tooltip" title="Restore" ng-if="field.removed">
                      <span class="pficon pficon-history"></span>
                    </button>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
          <input type="text" class="form-control" ng-model="$ctrl.emptyValueInfo" ng-if="$ctrl.emptyValueInfo" readonly/>
          <button type="button" class="btn-std entaxy-map-input-add-button"
                    ng-class="{'btn-std-ignore-error': $ctrl.items && $ctrl.items.length > 0}"
                    ng-if="!$ctrl.readonly" ng-click="$ctrl.add()" set-focused="$ctrl.setFocused">
            <span class="pficon pficon-add-circle-o"></span>
            <span>{{$ctrl.addItemTitle}}</span>
          </button>
        `,
        controller: entaxyMapInputController
    })
    .name;

    function entaxyMapInputController() {
        let ctrl = this;

        ctrl.$onInit = function () {
            ctrl.addItemTitle = 'Add Property';
            if (!ctrl.items) {
                if (ctrl.model) {
                    ctrl.items = Object.entries(ctrl.model).map(([key, value]) => {
                        return {
                            key: key,
                            value: value
                        };
                    }).sort(Entaxy.compareBy('key'));
                } else {
                    ctrl.items = [];
                }
            }

            if (ctrl.items.length === 0 && ctrl.readonly) {
                ctrl.emptyValueInfo = '--Map is empty--';
            }

            if (!ctrl.duplicateKeys) {
                ctrl.duplicateKeys = new Set();
            }
        }

        ctrl.changeKey = function (field) {
            validateKey(field);
            updateDuplicatesStatus();
            updateErrorsState();

            updateModel();
        }

        ctrl.changeValue = function (field) {
            updateModel();
        }

        function validateKey(field) {
            if (field.key.trim().length === 0) {
                field.hasError = true;
            } else {
                let duplicates = getItemsByKey(field.key);

                if (duplicates.length > 1) {
                    ctrl.duplicateKeys.add(field.key);
                    duplicates.forEach(item => item.hasError = true);
                } else {
                    field.hasError = false;
                }
            }
        }

        function updateDuplicatesStatus() {
            let expiredDuplicateKeys = new Set();
            ctrl.duplicateKeys.forEach(duplicateKey => {
                let duplicates = getItemsByKey(duplicateKey);

                if (duplicates.length <= 1) {
                    expiredDuplicateKeys.add(duplicateKey);
                    duplicates.forEach(item => item.hasError = false);
                }
            });
            if (expiredDuplicateKeys.size === ctrl.duplicateKeys.size) {
                ctrl.duplicateKeys.clear();
            } else {
                expiredDuplicateKeys.forEach(expiredDuplicateKey => ctrl.duplicateKeys.delete(expiredDuplicateKey));
            }
        }

        function getItemsByKey(key) {
            return ctrl.items.filter(item => !item.removed && item.key === key);
        }

        function updateErrorsState() {
            ctrl.hasErrors = ctrl.items.filter(item => !item.removed && item.hasError).length === 0 ? false : true;
        }

        function updateModel() {
            if (!ctrl.hasErrors) {
                ctrl.model = ctrl.items.length > 0 ? {} : undefined;
                ctrl.items.forEach(item => {
                    if (!item.removed && !item.hasError) {
                        ctrl.model[item.key] = item.value;
                    }
                });
            }
        }

        ctrl.add = function () {
            ctrl.items.push({type: 'text', key: '', value: ''});
            validateKey(ctrl.items[ctrl.items.length - 1]);
            updateErrorsState();

            ctrl.setDirty();
        }

        ctrl.remove = function (field) {
            field.removed = true;
            field.hasError = false;

            updateDuplicatesStatus();
            updateErrorsState();

            updateModel();

            ctrl.setDirty();
        }

        ctrl.restore = function (field) {
            field.removed = false;

            validateKey(field);
            updateDuplicatesStatus();
            updateErrorsState();

            updateModel();

            ctrl.setDirty();
        }

        ctrl.setDirty = function () {
            if (ctrl.formController && !ctrl.formController.$dirty) {
                ctrl.formController.$setDirty();
            }
        }
    }

})(Entaxy || (Entaxy = {}));
