import featureAPI from '@/services/feature-api';
import { isNil } from 'lodash';
export function formatStringDate(stringDate) {
  const date = new Date(stringDate);
  if (date instanceof Date && !isNaN(date.valueOf())) {
    const formatted_date = date.getFullYear() + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + ' ' +
    ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);
    return formatted_date;
  }
  return stringDate;
}

export const statusChoices = [
  {
    name: 'Brouillon',
    value: 'draft',
  },
  {
    name: 'En attente de publication',
    value: 'pending',
  },
  {
    name: 'Publié',
    value: 'published',
  },
  {
    name: 'Archivé',
    value: 'archived',
  },
];

export function allowedStatus2change(user, isModerate, userStatus, isOwnFeature, currentRouteName) {
  if ( //* si 'super-admin'(superuser) admin, modérateur ou super contributeur, statuts toujours disponibles: Brouillon, Publié, Archivé
    user.is_superuser ||
      userStatus === 'Modérateur' ||
      userStatus === 'Administrateur projet' ||
      (userStatus === 'Super Contributeur' && !isModerate)
  ) {
    return statusChoices.filter((el) => el.value !== 'pending');
  } else if (userStatus === 'Super Contributeur' && isModerate) {
    return statusChoices.filter(
      (el) => el.value === 'draft' || el.value === 'pending'
    );
  } else if (userStatus === 'Contributeur') { //* cas particuliers du contributeur
    if (currentRouteName === 'ajouter-signalement' || !isOwnFeature) {
      //* même cas à l'ajout d'une feature ou si feature n'a pas été créé par le contributeur
      return isModerate
        ? statusChoices.filter(
          (el) => el.value === 'draft' || el.value === 'pending'
        )
        : statusChoices.filter(
          (el) => el.value === 'draft' || el.value === 'published'
        );
    } else {
      //* à l'édition d'une feature et si le contributeur est l'auteur de la feature
      return isModerate
        ? statusChoices.filter(
          (el) => el.value !== 'published' //* toutes sauf "Publié"
        )
        : statusChoices.filter(
          (el) => el.value !== 'pending' //* toutes sauf "En cours de publication"
        );
    }
  }
  return [];
}

export function transformProperties(prop) {
  const type = typeof prop;
  const date = new Date(prop);
  const regInteger = /^-*?\d+$/;
  const regFloat = /^-*?\d*?\.\d+$/;
  const regText = /[\r\n]/;
  if (type === 'boolean' || (type === 'string' && (prop.toLowerCase() === 'true' || prop.toLowerCase() === 'False'))) {
    return 'boolean';
  } else if ((regInteger.test(prop) || Number.isSafeInteger(prop)) && prop !== 0) { // in case the value is 0, since it can be either float or integer, do not set to integer https://redmine.neogeo.fr/issues/16934
    return 'integer';
  } else if (
    type === 'string' &&
    ['/', ':', '-'].some((el) => prop.includes(el)) && // check for chars found in datestring
    date instanceof Date &&
    !isNaN(date.valueOf())
  ) {
    return 'date';
  } else if (regFloat.test(prop) ||  type === 'number' && !isNaN(parseFloat(prop)) || prop === 0) { // in case the value is 0, since it can be either float or integer, by default set as a float
    return 'decimal';
  } else if (regText.test(prop)) {
    return 'text';
  }
  return 'char'; //* string by default, most accepted type in database
}

export function objIsEmpty(obj) {
  for(const prop in obj) {
    if(Object.hasOwn(obj, prop)) {
      return false;
    }
  }

  return true;
}

export const reservedKeywords = [
  // todo : add keywords for mapstyle (strokewidth...)
  'id',
  'title',
  'description',
  'status',
  'created_on',
  'updated_on',
  'archived_on',
  'deletion_on',
  'feature_type',
  'feature_id',
  'display_creator',
  'display_last_editor',
  'project',
  'creator',
  'lat',
  'lon'
];

export const customFieldTypeChoices = [
  { name: 'Booléen', value: 'boolean' },
  { name: 'Chaîne de caractères', value: 'char' },
  { name: 'Date', value: 'date' },
  { name: 'Liste de valeurs', value: 'list' },
  { name: 'Liste de valeurs pré-enregistrées', value: 'pre_recorded_list' },
  { name: 'Liste à choix multiples', value: 'multi_choices_list' },
  { name: 'Nombre entier', value: 'integer' },
  { name: 'Nombre décimal', value: 'decimal' },
  { name: 'Texte multiligne', value: 'text' },
];

export const featureNativeFields = [
  { name: 'status', label: 'Statut', field_type: 'Champ GéoContrib' },
  { name: 'feature_type', label: 'Type', field_type: 'Champ GéoContrib' },
  { name: 'updated_on', label: 'Dernière mise à jour', field_type: 'Champ GéoContrib' },
  { name: 'created_on', label: 'Date de création', field_type: 'Champ GéoContrib' },
  { name: 'display_creator', label: 'Auteur', field_type: 'Champ GéoContrib' },
  { name: 'display_last_editor', label: 'Dernier éditeur', field_type: 'Champ GéoContrib' },
];

export const formatDate = (current_datetime) => {
  let formatted_date = current_datetime.getFullYear() + '-' + ('0' + (current_datetime.getMonth() + 1)).slice(-2) + '-' + ('0' + current_datetime.getDate()).slice(-2) + ' ' +
    ('0' + current_datetime.getHours()).slice(-2) + ':' + ('0' + current_datetime.getMinutes()).slice(-2);
  return formatted_date;
};

export const retrieveFeatureProperties = async (feature, featureTypes, projectSlug) => {
  const properties = feature.getProperties();
  let { feature_type, status, updated_on, created_on, creator, display_last_editor, index } = properties;
  
  if (creator) { 
    creator = creator.full_name ? `${creator.first_name} ${creator.last_name}` : creator.username;
  } else if (properties.feature_id) {
    //* if *** MVT *** feature, retrieve display_creator and display_last_editor by fetching the feature details from API
    const fetchedFeature = await featureAPI.getProjectFeature(projectSlug, properties.feature_id);
    if (fetchedFeature) {
      creator = fetchedFeature.properties.display_creator;
      display_last_editor = fetchedFeature.properties.display_last_editor;
      feature_type = fetchedFeature.properties.feature_type;
    }
  }
  
  if (featureTypes && feature_type) {
    feature_type = featureTypes.find((el) => el.slug === (feature_type.slug || feature_type));
  }
  
  if (updated_on && !isNaN(new Date(updated_on))) { //* check if date is already formatted
    updated_on = formatDate(new Date(updated_on));
  }
  if (created_on && !isNaN(new Date(created_on))) { //* check if date is already formatted
    created_on = formatDate(new Date(created_on));
  }
  
  if (status) {
    if (status.label) { //* when the label is already in the feature
      status = status.label;
    } else if (featureTypes) { //* if not, retrieve the name/label from the list
      status = statusChoices.find((el) => el.value === status).name;
    }
  }

  return { feature_type, status, updated_on, created_on, creator, display_last_editor, index };
};

export function findXformValue(feature, customField) {
  if (!feature) return null;
  if (feature.properties) {
    return feature.properties[customField.name] || null;
  } else if (feature.feature_data) {
    const field = feature.feature_data.find((el) => el.label === customField.label);
    return field ? field.value : null;
  }
  return null;
}

export function isXtraFormActive(extraForms, config) { // return true if no config or if the condition is fullfilled
  if (config) { // if conditional field configuration is not null
    // get name and value in condition
    const { conditionField, conditionValue } = config;
    // get the customForm which activates conditional field
    const conditioningXForm = extraForms.find((xForm) => xForm.name === conditionField);
    // check if the conditioning extraform value match the condition value
    if (conditioningXForm) {
      // if the values to compare are null or undefined the field can't be activated
      if (isNil(conditioningXForm.value) || isNil(conditionValue)) {
        return false;
      } else if (Array.isArray(conditionValue) && Array.isArray(conditioningXForm.value)) { // case of multiple list or prerecorded values list
        return conditioningXForm.value.some((value) => conditionValue.includes(value));
      } else if (typeof conditioningXForm.value === 'object' && conditioningXForm.value.label) { // case of simple list
        return conditioningXForm.value.label === conditionValue.label;
      } else {
        return conditioningXForm.value === conditionValue; // more simple case of other fields
      } 
    }
  }
  return true;
}

export function checkDeactivatedValues(extraForms) {
  // if changes occured, update extraForms array with freshly checked active customForms
  let newExtraForms = extraForms.map((xForm) => { // we use 'deactivate' instead of 'activate' because at initialization this property cannot be evaluated ...
    const isDeactivated = !isXtraFormActive(extraForms, xForm.conditional_field_config);  // ... if the component is not created to set this property, thus no extra form would appear at all
    // toggle value to null to deactivate other fields conditioned by it
    if (isDeactivated) {
      xForm['value'] = null;
    }
    return { ...xForm, ['isDeactivated']: isDeactivated };
  });
  return newExtraForms;
}

export function checkFieldForcedValue(field, extraForms) {
  field['disabled'] = false; //* create a property disabled and (re)set to false by default
  if (field.forced_value_config) {
    //* loop over each forced value config for this extraForm
    for (const config of field.forced_value_config) {
      //* find the extraForm field conditioning the forced value
      const conditioningField = extraForms.find((xtraForm) => xtraForm.name === config.conditionField);
      //* if found check that its value match the condtionValue
      if (conditioningField && conditioningField.value === config.conditionValue) {
        //* set this value with the forced value and disable the form field
        field.value = config.forcedValue;
        field.disabled = true;
      }
    }
  }
  return field;
}

export function activateFieldsNforceValues(extraForms) {
  for (const [index, field] of extraForms.entries()) {
    const checkedField = checkFieldForcedValue(field, extraForms);
    //* each time a value changes, call this function recursively, until there is no more change
    if (checkedField.value !== field.value) {
      extraForms[index] = checkedField; //* update the value in extraForms
      activateFieldsNforceValues(extraForms); //* call the function with new extraForms
    }
  }
  //* when no more changes detected in the loop, check for deactivated extraForms
  extraForms = checkDeactivatedValues(extraForms);
  //* return extraForms from the lastly called function
  return extraForms;
}