'use strict';
define(function() {
  var FormsHelper = function(
    $translate,
    $filter,
    $rootScope,
    gcPopup,
    ConfigFactory,
    gcChainPopup,
    $modal,
    FeatureTypeFactory,
    AdvancedEditionFactory,
    RightsFactory
  ) {
    var FIELD_IS_REQUIRED_MESSAGE = null;

    const TEMPLATE_QUERY = {
      querydata: {},
      partdata: {},
      selop: '=',
      where: '1=10',
      casesensitive: true,
    };

    const OPERANDES = [
      {
        name: 'equals',
        value: '=',
      },
      {
        name: 'different',
        value: '<>',
      },
      {
        name: 'gt',
        value: '>',
      },
      {
        name: 'gte',
        value: '>=',
      },
      {
        name: 'lt',
        value: '<',
      },
      {
        name: 'lte',
        value: '<=',
      },
      {
        name: 'like',
        value: '%',
      },
    ];

    if (
      angular.isDefined($modal) &&
      angular.isDefined(gcChainPopup) &&
      !gcChainPopup.isInitialized()
    )
      gcChainPopup.setModalProvider($modal);

    var editScope = null;
    var scope = $rootScope.$new();
    scope.formTemplates = {};

    var cache = {};

    function addToCache(ftid, attName, attValue) {
      if (!cache[ftid]) cache[ftid] = {};

      var ftidCacheContainer = cache[ftid];

      if (attValue) ftidCacheContainer[attName] = attValue;
    }

    function updatePropertiesFromCache(ftid, properties) {
      if (!cache[ftid]) return;

      var ftidCacheContainer = cache[ftid];
      for (var key in ftidCacheContainer)
        properties[key] = ftidCacheContainer[key];
    }


    function getFtiFieldByName(fti, fieldName) {
      for (var i = 0; i < fti.attributes.length; i++) {
        var attr = fti.attributes[i];
        if (attr.name === fieldName) return attr;
      }
      return null;
    }

    function getLinkObjectToRelQueryParentMethod(inscope, rScope) {
      return function(feat) {
        console.log(inscope);
        console.log(rScope);
        inscope.query.selop = inscope.operandes[0].value;
        inscope.query.partdata[inscope.query.querydata.filterfield.name] =
          feat.properties[rScope.seekField.name];
        inscope.processSearch();
        rScope.chainpopup.destroy();
        if (angular.isDefined(rScope.filterFieldWatcher)) {
          rScope.filterFieldWatcher();
          delete rScope.filterFieldWatcher;
        }
      };
    }

    function getProcessSearch(rScope) {
      return function() {
        if (
          rScope.query.partdata[rScope.query.querydata.filterfield.name] &&
          rScope.query.partdata[rScope.query.querydata.filterfield.name] != ''
        ) {
          var where = '';
          if (rScope.query.selop == '%') {
            var likeOper = rScope.query.casesensitive ? 'LIKE' : 'ILIKE';
            where =
              rScope.query.querydata.filterfield.name +
              ' ' +
              likeOper +
              " '%" +
              rScope.query.partdata[rScope.query.querydata.filterfield.name] +
              "%'";
          } else
            where +=
              rScope.query.querydata.filterfield.name +
              rScope.query.selop +
              "'" +
              rScope.query.partdata[rScope.query.querydata.filterfield.name] +
              "'";

          rScope.query.where = where;
        }
      };
    }

    function getRelCloseForm(rScope) {
      return function() {
        if (rScope.chainpopup != undefined) {
          rScope.chainpopup.destroy();
        }

        if (angular.isDefined(rScope.filterFieldWatcher)) {
          rScope.filterFieldWatcher();
          delete rScope.filterFieldWatcher;
        }
      };
    }

    function openRelatedSearchForm(
      fti,
      inscope,
      searchField,
      relatedFti,
      relatedDefaultSearchField
    ) {
      var rScope = $rootScope.$new();

      rScope.filterFieldWatcher = rScope.$watch(
        'query.querydata.filterfield',
        function(newval, oldval) {
          if (newval != oldval)
            checkFieldAndOpenRelationSearchForm(relatedFti, rScope, newval);
        }
      );

      rScope.query = angular.copy(TEMPLATE_QUERY);
      rScope.operandes = angular.copy(OPERANDES);
      rScope.maintitle =
        $filter('translate')('networkedit.relatedTableQueryTitle') +
        ' : ' +
        relatedFti.name;
      rScope.preventhighlightdata = relatedFti.typeInfo == 'NG';
      rScope.preventmultiselection = true;
      rScope.currentRelatedFti = relatedFti;
      rScope.query.querydata.filterfield = relatedDefaultSearchField;
      rScope.seekField = relatedDefaultSearchField;
      rScope.relatedActions = [
        {
          name: 'relateTo',
          icone: 'fa fa-external-link',
          callFunction: getLinkObjectToRelQueryParentMethod(inscope, rScope),
        },
      ];
      rScope.processSearch = getProcessSearch(rScope);
      rScope.hideForm = inscope.hideForm;
      rScope.closeForm = inscope.closeForm;
      rScope.closeRelForm = getRelCloseForm(rScope);

      rScope.chainpopup = inscope.chainpopup;
      rScope.chainpopup.openNext({
        scope: rScope,
        template:
          'js/XG/widgets/mapapp/bizedition/views/tables_query_editor.html',
        showClose: true,
        hidemin: true,
      });
    }

    function checkFieldAndOpenRelationSearchForm(fti, inscope, searchField) {
      if (searchField.type == 'java.lang.Integer' && fti.relations.length > 0) {
        var relatedFti = null;
        var relatedDefaultSearchField = null;
        fti.relations.forEach(function(ftiRel) {
          if (
            relatedFti == null &&
            angular.isDefined(ftiRel.fieldStart) &&
            ftiRel.fieldStart === searchField.name &&
            angular.isDefined(ftiRel.idStart)
          ) {
            relatedFti = FeatureTypeFactory.getFeatureByUid(ftiRel.idStart);
            if (ftiRel.fieldEnd)
              relatedDefaultSearchField = getFtiFieldByName(
                relatedFti,
                ftiRel.fieldEnd
              );
          }
        });

        if (relatedFti != null && fti.uid != relatedFti.uid)
          openRelatedSearchForm(
            fti,
            inscope,
            searchField,
            relatedFti,
            relatedDefaultSearchField
          );
      }
    }

    function openEditRows(fti, inscope, optionalTitle) {
      inscope.filterFieldWatcher = inscope.$watch(
        'query.querydata.filterfield',
        function(newval, oldval) {
          if (newval != oldval)
            checkFieldAndOpenRelationSearchForm(fti, inscope, newval);
        }
      );

      inscope.query = angular.copy(TEMPLATE_QUERY);
      inscope.operandes = angular.copy(OPERANDES);
      inscope.maintitle =
        optionalTitle == null
          ? $filter('translate')('networkedit.elecmt.editrowstitle') +
            ' : ' +
            fti.name
          : $filter('translate')('networkedit.elecmt.sectionsEditorTitle');
      inscope.preventhighlightdata = fti.typeInfo == 'NG';
      inscope.preventmultiselection = true;
      inscope.chainpopup = gcChainPopup.openInChain({
        scope: inscope,
        template: 'js/XG/widgets/mapapp/bizedition/views/tables_editor.html',
        showClose: true,
        hidemin: true,
        onclose: function() {
          if (inscope.editsession) inscope.editsession.close();
          if (angular.isDefined(closeFn)) closeFn.call();
        },
      });
    }

    // function getGroupedAttribute(authorizedAttributes) {
    //     authorizedAttributes.forEach(function (attr)) {
    //         if attr
    //     }

    //     return
    // };

    function openTemplate(
      feature,
      fti,
      inscope,
      isUpdate,
      closeFn,
      inChain,
      indirect,
      multiEdit
    ) {
      inscope.multiEdit = multiEdit;
      inscope.uploadfile = {};
      if (inscope.chainpopup != undefined && inChain != true)
        inscope.chainpopup.destroy();
      inscope.currentFti = fti;
      inscope.currentFeature = feature;

      if (Array.isArray(feature)) inscope.groupedAttribute = true;

      console.log(scope.formTemplates[fti.uid]);
      if ($rootScope.xgos) {
        const isAdmin = $rootScope.xgos.isroot || $rootScope.xgos.isadmin;
        inscope.authorizedAttributes = RightsFactory.getUserWriteOrReadRightsAttributes($rootScope.xgos.user, fti, isAdmin);
      } else {
        inscope.authorizedAttributes = [];
        console.error('$rootScope.xgos = ', $rootScope.xgos);
      }
      inscope.currentProperties =
        feature instanceof ol.Feature
          ? feature.getProperties()
          : feature.properties;

      inscope.currentEditFeature = {
        current: {
          properties: inscope.currentProperties,
        },
      };

      if (feature instanceof ol.Feature && feature.getId())
        inscope.currentEditFeature.current.id = feature.getId();
      else if (feature instanceof Object && feature.id)
        inscope.currentEditFeature.current.id = feature.id;

      inscope.formTemplates = scope.formTemplates;

      // if(multiEdit) {
      //     inscope.authorizedAttributes = getGroupedAttribute(inscope.authorizedAttributes)
      //     console.log("Trolol !")
      // }

      // [""4528ecb2-b174-4f27-864d-880cd5130dc4""].data.fields[2].edit_group

      console.log(inscope);
      inscope.isupdate = isUpdate;
      if (inscope.chainpopup != undefined && inChain == true)
        inscope.chainpopup.openNext({
          scope: inscope,
          template: indirect
            ? 'js/XG/widgets/mapapp/bizedition/views/attribute_indirect_modal.html'
            : 'js/XG/widgets/mapapp/bizedition/views/attribute_modal.html',
          showClose: true,
          hidemin: true,
          onclose: function() {
            if (inscope.editsession) inscope.editsession.close();
            if (angular.isDefined(closeFn)) closeFn.call();
          },
        });
      else
        inscope.chainpopup = gcChainPopup.openInChain({
          scope: inscope,
          template: indirect
            ? 'js/XG/widgets/mapapp/bizedition/views/attribute_indirect_modal.html'
            : 'js/XG/widgets/mapapp/bizedition/views/attribute_modal.html',
          showClose: true,
          hidemin: true,
          onclose: function() {
            if (inscope.editsession) inscope.editsession.close();
            if (angular.isDefined(closeFn)) closeFn.call();
          },
        });
    }

    function executeForm(
      action,
      feature,
      fti,
      inscope,
      isUpdate,
      closeFn,
      inChain,
      indirect,
      multiEdit
    ) {
      if (scope.formTemplates[fti.uid + '__' + action.form])
        openTemplate(
          feature,
          fti,
          inscope,
          isUpdate,
          closeFn,
          inChain,
          indirect,
          multiEdit
        );
      else {
        ConfigFactory.get(action.type, action.form).then(
          function(res) {
            var formTemplate = res.data;
            scope.formTemplates[fti.uid] = formTemplate;
            scope.formTemplates[fti.uid + '__' + action.form] = formTemplate;
            openTemplate(
              feature,
              fti,
              inscope,
              isUpdate,
              closeFn,
              inChain,
              indirect,
              multiEdit
            );
          },
          function() {
            console.log('form does not exist');
            scope.formTemplates[fti.uid] = null;
            scope.formTemplates[fti.uid + '__' + action.form] = null;
            openTemplate(
              feature,
              fti,
              inscope,
              isUpdate,
              closeFn,
              inChain,
              indirect,
              multiEdit
            );
          }
        );
      }
    }

    function loadForm(action, fti) {
      if (scope.formTemplates[fti.uid]) return scope.formTemplates[fti.uid];
      else {
        var promise = ConfigFactory.get(
          action.type,
          action.form,
          action.application_name
        );
        promise.then(
          function(res) {
            var formTemplate = res.data;
            scope.formTemplates[fti.uid] = formTemplate;
          },
          function() {
            console.log('form does not exist');
            scope.formTemplates[fti.uid] = null;
          }
        );

        return promise;
      }
    }

    function checkAndGetValidScope(inscope) {
      return angular.isUndefined(inscope) || inscope == null
        ? editScope
        : inscope;
    }

    function initEditScope(eScope) {
      editScope = eScope;
    }

    function openForm(fti, feature, inscope, closeFn, inChain) {
      getOrBuildFeatureId(feature);
      inscope = checkAndGetValidScope(inscope);
      if (fti.defaultsAction) {
        var selectedAction = fti.defaultsAction;
        if (
          $filter('translate')('model.featuretypes.actions.form') ==
            selectedAction.actionType ||
          'FORMULAIRE' == selectedAction.actionType
        )
          executeForm(
            selectedAction,
            feature,
            fti,
            inscope,
            false,
            closeFn,
            inChain
          );
        else openTemplate(feature, fti, inscope, false, closeFn, inChain);
      } else openTemplate(feature, fti, inscope, false, closeFn, inChain);
    }

    function openIndirectUpdateForm(fti, feature, inscope, closeFn, inChain) {
      inscope = checkAndGetValidScope(inscope);
      if (fti.defaultsAction) {
        var selectedAction = fti.defaultsAction;
        if (
          $filter('translate')('model.featuretypes.actions.form') ==
            selectedAction.actionType ||
          'FORMULAIRE' == selectedAction.actionType
        )
          executeForm(
            selectedAction,
            feature,
            fti,
            inscope,
            true,
            closeFn,
            inChain,
            true
          );
        else openTemplate(feature, fti, inscope, true, closeFn, inChain, true);
      } else openTemplate(feature, fti, inscope, true, closeFn, inChain, true);
    }

    function openUpdateForm(
      fti,
      feature,
      inscope,
      closeFn,
      inChain,
      multiEdit
    ) {
      inscope = checkAndGetValidScope(inscope);
      if (fti.defaultsAction) {
        var selectedAction = fti.defaultsAction;
        if (
          $filter('translate')('model.featuretypes.actions.form') ==
            selectedAction.actionType ||
          'FORMULAIRE' == selectedAction.actionType
        )
          executeForm(
            selectedAction,
            feature,
            fti,
            inscope,
            true,
            closeFn,
            inChain,
            null,
            multiEdit
          );
        else openTemplate(feature, fti, inscope, true, closeFn, inChain);
      } else openTemplate(feature, fti, inscope, true, closeFn, inChain);
    }

    function getFtiForm(fti) {
      if (fti && fti.defaultsAction) {
        var selectedAction = fti.defaultsAction;
        if (
          $filter('translate')('model.featuretypes.actions.form') ==
            selectedAction.actionType ||
          'FORMULAIRE' == selectedAction.actionType
        )
          return loadForm(selectedAction, fti);
        else return null;
      } else return null;
    }

    function loadForms(ftis) {
      ftis.forEach(function(fti) {
        if (angular.isString(fti))
          fti = FeatureTypeFactory.getFeatureByUid(fti);

        getFtiForm(fti);
      });
    }

    function getRequiredFields(curTemplate) {
      var requiredFields = [];
      curTemplate.fields.forEach(function(field) {
        if (field.required && field.config && field.config.name)
          requiredFields.push(field.config.name);
      });
      return requiredFields;
    }

    function getOrBuildFeatureId(feature) {
      if (feature instanceof ol.Feature) {
        return feature.get('id');
      } else if (feature instanceof Object) {
        if (feature.properties) {
          if (feature.properties.id) {
            return feature.properties.id;
          }
        }
      } else return feature;
    }


    function requiredFieldsAreValid(scope) {
      if (FIELD_IS_REQUIRED_MESSAGE == null)
        FIELD_IS_REQUIRED_MESSAGE = $filter('translate')(
          'model.featuretypes.attributes.fieldisrequired'
        );

      if (
        scope.formTemplates &&
        scope.currentFti &&
        scope.formTemplates[scope.currentFti.uid]
      ) {
        var templateform = scope.formTemplates[scope.currentFti.uid];
        console.log(scope.currentEditFeature);
        var hasTree = angular.isArray(templateform.data);
        var requiredFields = null;
        if (hasTree) {
          requiredFields = [];
          templateform.data.forEach(function(treeTemplate) {
            requiredFields = requiredFields.concat(
              getRequiredFields(treeTemplate.template)
            );
          });
        } else requiredFields = getRequiredFields(templateform.data);

        var allValid = true;
        if (requiredFields != null && requiredFields.length > 0) {
          requiredFields.forEach(function(fieldName) {
            if (
              scope.currentEditFeature &&
              scope.currentEditFeature.current &&
              scope.currentEditFeature.current.properties
            ) {
              if (
                angular.isDefined(
                  scope.currentEditFeature.current.properties[fieldName]
                )
              ) {
                var value =
                  scope.currentEditFeature.current.properties[fieldName];
                if (value == null || value == '') {
                  allValid = false;
                  require('toastr').error(
                    FIELD_IS_REQUIRED_MESSAGE.replace('FIELD_NAME', fieldName)
                  );
                }
              } else {
                allValid = false;
                require('toastr').error(
                  FIELD_IS_REQUIRED_MESSAGE.replace('FIELD_NAME', fieldName)
                );
              }
            }
          });
        }
        return allValid;
      }

      return true;
    }

    /**
     * Récupère l'identifiant de la popup contenant l'élément gceditsave (i.e popup.features.iddiv)
     * @return {object} elt élement jQuery du composant
     */
    const getIdDiv = (elt) => {
      if (elt && elt.length > 0) {
        const popupContainer = elt[0].closest('.popupContainer');
        if (popupContainer) {
          return popupContainer.id;
        }
      }
      return null;
    };

    return {
      getOrBuildFeatureId: getOrBuildFeatureId,
      initEditScope: initEditScope,
      openForm: openForm,
      openEditRows: openEditRows,
      openIndirectUpdateForm: openIndirectUpdateForm,
      openUpdateForm: openUpdateForm,
      getFtiForm: getFtiForm,
      loadForms: loadForms,
      addToCache: addToCache,
      updatePropertiesFromCache: updatePropertiesFromCache,
      requiredFieldsAreValid: requiredFieldsAreValid,
      checkFieldAndOpenRelationSearchForm: checkFieldAndOpenRelationSearchForm,
      executeForm: executeForm,
      getIdDiv: getIdDiv
    };
  };
  FormsHelper.$inject = [
    '$translate',
    '$filter',
    '$rootScope',
    'gcPopup',
    'ConfigFactory',
    'gcChainPopup',
    '$modal',
    'FeatureTypeFactory',
    'AdvancedEditionFactory',
    'RightsFactory'
  ];
  return FormsHelper;
});
