# -*- coding: utf-8 -*-

# For debugging
# NVIM_PYTHON_LOG_FILE=nvim.log NVIM_PYTHON_LOG_LEVEL=INFO nvim

from __future__ import absolute_import
import os

py = 'python3'

# detect python2
if 'VIRTUAL_ENV' in os.environ:
    py2 = os.path.join(os.environ['VIRTUAL_ENV'], 'bin', 'python2')
    if os.path.isfile(py2):
        py = 'python2'

from cm import register_source, getLogger, Base
register_source(name='cm-jedi',
                priority=9,
                abbreviation='Py',
                scoping=True,
                scopes=['python'],
                multi_thread=0,
                # disable early cache to minimize the issue of #116
                # early_cache=1,
                # The last two patterns is for displaying function signatures r'\(\s?', r',\s?'
                cm_refresh_patterns=[r'^(import|from).*\s', r'\.', r'\(\s?', r',\s?'],
                python=py,)

import re
import jedi

logger = getLogger(__name__)

class Source(Base):

    def __init__(self,nvim):
        Base.__init__(self, nvim)
        self._snippet_engine = nvim.vars['cm_completed_snippet_engine']

        # workaround for #62
        try:
            import resource
            import psutil
            mem = psutil.virtual_memory()
            resource.setrlimit(resource.RLIMIT_DATA, (mem.total/3, resource.RLIM_INFINITY))
        except Exception as ex:
            logger.exception("set RLIMIT_DATA failed. %s", ex)
            pass

    def cm_refresh(self,info,ctx,*args):

        path = ctx['filepath']
        typed = ctx['typed']

        # Ignore comment, also workaround jedi's bug #62
        if re.match(r'\s*#', typed):
            return

        src = self.get_src(ctx)
        if not src.strip():
            # empty src may possibly block jedi execution, don't know why
            logger.info('ignore empty src [%s]', src)
            return

        logger.info('context [%s]', ctx)

        # logger.info('jedi.Script lnum[%s] curcol[%s] path[%s] [%s]', lnum,len(typed),path,src)
        script = jedi.Script(src, ctx['lnum'], len(ctx['typed']), path)

        signature_text = ''
        signature = None
        try:
            signatures = script.call_signatures()
            logger.info('signatures: %s', signatures)
            if len(signatures)>0:
                signature = signatures[-1]
                params=[param.description for param in signature.params]
                signature_text = signature.name + '(' + ', '.join(params) + ')'
                logger.info("signature: %s, name: %s", signature, signature.name)
        except Exception as ex:
            logger.exception("get signature text failed %s", signature_text)

        is_import = False
        if re.search(r'^\s*(from|import)', typed):
            is_import = True

        if re.search(r'^\s*(?!from|import).*?[(,]\s*$', typed):
            if signature_text:
                matches = [dict(word='',empty=1,abbr=signature_text,dup=1),]
                # refresh=True
                # call signature popup doesn't need to be cached by the framework
                self.complete(info, ctx, ctx['col'], matches, True)
            return

        completions = script.completions()
        logger.info('completions %s', completions)

        matches = []

        for complete in completions:

            insert = complete.complete

            item = dict(word=ctx['base']+insert,
                        icase=1,
                        dup=1,
                        menu=complete.description,
                        info=complete.docstring()
                        )

            # Fix the user typed case
            if item['word'].lower()==complete.name.lower():
                item['word'] = complete.name

            # snippet support
            try:
                if (complete.type == 'function' or complete.type == 'class'):
                    self.render_snippet(item, complete, is_import)
            except Exception as ex:
                logger.exception("exception parsing snippet for item: %s, complete: %s", item, complete)

            matches.append(item)

        logger.info('matches %s', matches)
        # workaround upstream issue by letting refresh=True. #116
        self.complete(info, ctx, ctx['startcol'], matches)

    def render_snippet(self, item, complete, is_import):

        doc = complete.docstring()

        # This line has performance issue
        # https://github.com/roxma/nvim-completion-manager/issues/126
        # params = complete.params

        fundef = doc.split("\n")[0]

        params = re.search(r'(?:_method|' + re.escape(complete.name) + ')' + r'\((.*)\)', fundef)

        if params:
            item['menu'] = fundef

        logger.debug("building snippet [%s] type[%s] doc [%s]", item['word'], complete.type, doc)

        if params and not is_import:

            num = 1
            placeholders = []
            snip_args = ''

            params = params.group(1)
            if params != '':
                params = params.split(',')
                cnt = 0
                for param in params:
                    cnt += 1
                    if "=" in param or "*" in param or param[0] == '[':
                        break
                    else:
                        name = param.strip('[').strip(' ')

                        # Note: this is not accurate
                        if cnt==1 and (name=='self' or name=='cls'):
                            continue

                        ph = self.snippet_placeholder(num, name)
                        placeholders.append(ph)
                        num += 1

                        # skip optional parameters
                        if "[" in param:
                            break

                snip_args = ', '.join(placeholders)
                if len(placeholders) == 0:
                    # don't jump out of parentheses if function has
                    # parameters
                    snip_args = self.snippet_placeholder(1)

            ph0 = self.snippet_placeholder(0)
            snippet = '%s(%s)%s' % (item['word'], snip_args, ph0)

            item['snippet'] = snippet
            logger.debug('snippet: [%s] placeholders: %s', snippet, placeholders)