"""Elastic search fields for Resolwe."""
import elasticsearch_dsl as dsl

# pylint: disable=invalid-name
# Process type analyzer. During indexing we tokenize by type paths, during search,
# we do not tokenize at all.
process_type_tokenizer = dsl.tokenizer('process_type_tokenizer', type='path_hierarchy', delimiter=':')
process_type_analyzer = dsl.analyzer('process_type_analyzer', tokenizer=process_type_tokenizer, filter=['lowercase'])
process_type_search_analyzer = dsl.analyzer('process_type_search_analyzer', tokenizer='keyword', filter=['lowercase'])

# Name analyzer.
name_analyzer = dsl.analyzer(
    'name_analyzer',
    type='pattern',
    # The pattern matches token separators.
    pattern=r'''
          ([^\p{L}\d]+)                 # swallow non letters and numbers,
        | (?<=\D)(?=\d)                 # or non-number followed by number,
        | (?<=\d)(?=\D)                 # or number followed by non-number,
    ''',
    flags='CASE_INSENSITIVE|COMMENTS',
    lowercase=True,
)

# During indexing, we lowercase terms and tokenize using edge_ngram.
ngrams_analyzer = dsl.analyzer(
    'ngrams_index',
    tokenizer='standard',
    filter=[
        'lowercase',
        dsl.token_filter(
            'ngrams_filter',
            type='edgeNGram',
            min_gram=1,
            max_gram=15,
        ),
    ],
)
# During search, we only lowercase terms.
ngrams_search_analyzer = dsl.analyzer(
    'ngrams_search',
    tokenizer='standard',
    filter=['lowercase'],
)
# pylint: enable=invalid-name


class RawKeywordSubfieldMixin:
    """String field with a 'raw' subfield (e.g. for sorting)."""

    def __init__(self, *args, **kwargs):
        """Construct field."""
        kwargs.setdefault('fields', {})['raw'] = {'type': 'keyword'}
        super().__init__(*args, **kwargs)


class NgramsSubfieldMixin:
    """String field with a 'ngrams' subfield (e.g. for autocomplete)."""

    def __init__(self, *args, **kwargs):
        """Construct field."""
        kwargs.setdefault('fields', {})['ngrams'] = {
            'type': 'text',
            'analyzer': ngrams_analyzer,
            'search_analyzer': ngrams_search_analyzer,
        }
        super().__init__(*args, **kwargs)


class Name(RawKeywordSubfieldMixin, NgramsSubfieldMixin, dsl.Text):
    """Field for names supporting term matches.

    Includes a 'raw' and 'ngrams' subfields for sorting and
    autocomplete.
    """

    def __init__(self, *args, **kwargs):
        """Construct field."""
        kwargs.setdefault('analyzer', name_analyzer)
        super().__init__(*args, **kwargs)


class ProcessType(RawKeywordSubfieldMixin, dsl.Text):
    """Field for process type supporting hierarchical type matches.

    Includes a 'raw' subfield for sorting.
    """

    def __init__(self, *args, **kwargs):
        """Construct field."""
        kwargs.setdefault('analyzer', process_type_analyzer)
        kwargs.setdefault('search_analyzer', process_type_search_analyzer)
        super().__init__(*args, **kwargs)


class User(NgramsSubfieldMixin, dsl.Text):
    """Field for users supporting partial matches."""

    pass


class Slug(NgramsSubfieldMixin, dsl.Keyword):
    """Field for slugs supporting partial matches."""

    pass
