import { fileFetcher } from '../core/file_fetcher';
import { localizer } from '../core/localizer';
import { t } from '../core/localizer';
import { presetManager } from '../presets';
import { validationIssue, validationIssueFix } from '../core/validation';
import { actionChangeTags } from '../actions/change_tags';


let _discardNameRegexes = [];

export function validationSuspiciousName() {
  const type = 'suspicious_name';
  const keysToTestForGenericValues = ['amenity', 'building', 'leisure', 'man_made', 'shop', 'tourism'];

  // A concern here in switching to async data means that `_nsiFilters` will not
  // be available at first, so the data on early tiles may not have tags validated fully.

  fileFetcher.get('nsi_filters')
    .then(filters => {
      // known list of generic names (e.g. "bar")
      _discardNameRegexes = filters.discardNames
        .map(discardName => new RegExp(discardName, 'i'));
    })
    .catch(() => { /* ignore */ });


  function isDiscardedSuggestionName(lowercaseName) {
    return _discardNameRegexes.some(regex => regex.test(lowercaseName));
  }

  // test if the name is just the key or tag value (e.g. "park")
  function nameMatchesRawTag(lowercaseName, tags) {
    for (let i = 0; i < keysToTestForGenericValues.length; i++) {
      let key = keysToTestForGenericValues[i];
      let val = tags[key];
      if (val) {
        val = val.toLowerCase();
        if (key === lowercaseName ||
          val === lowercaseName ||
          key.replace(/\_/g, ' ') === lowercaseName ||
          val.replace(/\_/g, ' ') === lowercaseName) {
          return true;
        }
      }
    }
    return false;
  }

  function isGenericName(name, tags) {
    name = name.toLowerCase();
    return nameMatchesRawTag(name, tags) || isDiscardedSuggestionName(name);
  }

  function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
    return new validationIssue({
      type: type,
      subtype: 'generic_name',
      severity: 'warning',
      message: function(context) {
        let entity = context.hasEntity(this.entityIds[0]);
        if (!entity) return '';
        let preset = presetManager.match(entity, context.graph());
        let langName = langCode && localizer.languageName(langCode);
        return t('issues.generic_name.message' + (langName ? '_language' : ''),
          { feature: preset.name(), name: genericName, language: langName }
        );
      },
      reference: showReference,
      entityIds: [entityId],
      hash: nameKey + '=' + genericName,
      dynamicFixes: function() {
        return [
          new validationIssueFix({
            icon: 'iD-operation-delete',
            title: t('issues.fix.remove_the_name.title'),
            onClick: function(context) {
              let entityId = this.issue.entityIds[0];
              let entity = context.entity(entityId);
              let tags = Object.assign({}, entity.tags);   // shallow copy
              delete tags[nameKey];
              context.perform(
                actionChangeTags(entityId, tags), t('issues.fix.remove_generic_name.annotation')
              );
            }
          })
        ];
      }
    });

    function showReference(selection) {
      selection.selectAll('.issue-reference')
        .data([0])
        .enter()
        .append('div')
        .attr('class', 'issue-reference')
        .text(t('issues.generic_name.reference'));
    }
  }

  function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
    return new validationIssue({
      type: type,
      subtype: 'not_name',
      severity: 'warning',
      message: function(context) {
        const entity = context.hasEntity(this.entityIds[0]);
        if (!entity) return '';
        const preset = presetManager.match(entity, context.graph());
        const langName = langCode && localizer.languageName(langCode);
        return t('issues.incorrect_name.message' + (langName ? '_language' : ''),
          { feature: preset.name(), name: incorrectName, language: langName }
        );
      },
      reference: showReference,
      entityIds: [entityId],
      hash: nameKey + '=' + incorrectName,
      dynamicFixes: function() {
        return [
          new validationIssueFix({
            icon: 'iD-operation-delete',
            title: t('issues.fix.remove_the_name.title'),
            onClick: function(context) {
              const entityId = this.issue.entityIds[0];
              const entity = context.entity(entityId);
              let tags = Object.assign({}, entity.tags);   // shallow copy
              delete tags[nameKey];
              context.perform(
                actionChangeTags(entityId, tags), t('issues.fix.remove_mistaken_name.annotation')
              );
            }
          })
        ];
      }
    });

    function showReference(selection) {
      selection.selectAll('.issue-reference')
        .data([0])
        .enter()
        .append('div')
        .attr('class', 'issue-reference')
        .text(t('issues.generic_name.reference'));
    }
  }


  let validation = function checkGenericName(entity) {
    // a generic name is okay if it's a known brand or entity
    if (entity.hasWikidata()) return [];

    let issues = [];
    const notNames = (entity.tags['not:name'] || '').split(';');

    for (let key in entity.tags) {
      const m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
      if (!m) continue;

      const langCode = m.length >= 2 ? m[1] : null;
      const value = entity.tags[key];
      if (notNames.length) {
        for (let i in notNames) {
          const notName = notNames[i];
          if (notName && value === notName) {
            issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
            continue;
          }
        }
      }
      if (isGenericName(value, entity.tags)) {
        issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
      }
    }

    return issues;
  };


  validation.type = type;

  return validation;
}

@@ -462,39 +462,103 @@
  = %5B
-'amenity', 'building', 'leisure
+%0A    'aerialway', 'aeroway', 'amenity', 'building', 'craft', 'highway',%0A    'leisure', 'railway
 ', '
@@ -567,16 +567,26 @@
 n_made',
+ 'office',
  'shop',
@@ -595,16 +595,31 @@
 tourism'
+, 'waterway'%0A  
 %5D;%0A%0A  //

Check feature names against additional generic tag keys/values