"""Get the "last updated" time for each Sphinx page from Git."""
import datetime
from pathlib import Path
import subprocess

from sphinx.locale import _
from sphinx.util.i18n import format_date
from sphinx.util.logging import getLogger


__version__ = '0.1.1'


logger = getLogger(__name__)


class NotInRepository(Exception):
    """The file is not in a Git repo."""


class TooShallow(Exception):
    """The file was last updated in the initial commit of a shallow clone."""


def get_datetime(path):
    """Obtain the "author time" for *path* from Git."""
    path = Path(path)

    def run_command(cmd):
        return subprocess.check_output(
            cmd,
            cwd=path.parent,
            stderr=subprocess.PIPE,
            universal_newlines=True,
        )

    result = run_command(
        ['git', 'log', '-n1', '--pretty=tformat:%at%n%P', '--', path.name])
    if not result:
        raise NotInRepository(path)
    timestamp, parents = result.splitlines()
    if not parents:
        # --is-shallow-repository is available since Git 2.15.
        result = run_command(['git', 'rev-parse', '--is-shallow-repository'])
        if result.rstrip('\n') == 'true':
            raise TooShallow(path)
    return datetime.datetime.fromtimestamp(int(timestamp))


def _html_page_context(app, pagename, templatename, context, doctree):
    context['last_updated'] = None
    lufmt = app.config.html_last_updated_fmt
    if lufmt is None or 'sourcename' not in context:
        return
    sourcefile = Path(app.confdir, pagename + context['page_source_suffix'])
    dates = []
    try:
        dates.append(get_datetime(sourcefile))
    except subprocess.CalledProcessError as e:
        logger.warning('Git error:\n%s', e.stderr, location=pagename)
        return
    except FileNotFoundError as e:
        logger.warning('"git" command not found: %s', e, location=pagename)
        return
    except NotInRepository:
        if not app.config.git_untracked_show_sourcelink:
            del context['sourcename']
        if not app.config.git_untracked_check_dependencies:
            return
        shallow = False
    except TooShallow:
        shallow = True

    # Check dependencies (if they are in a Git repo)
    for dep in app.env.dependencies[pagename]:
        path = Path(app.confdir, dep)
        try:
            date = get_datetime(path)
        except Exception:
            continue
        else:
            dates.append(date)

    if not dates:
        if shallow:
            logger.info(
                '%s: Git clone too shallow', __name__, location=pagename)
        return

    context['last_updated'] = format_date(
        lufmt or _('%b %d, %Y'),
        date=max(dates),
        language=app.config.language)


def _config_inited(app, config):
    if config.html_last_updated_fmt is None:
        config.html_last_updated_fmt = ''


def setup(app):
    """Sphinx extension entry point."""
    app.require_sphinx('1.8')  # For "config-inited" event
    app.connect('html-page-context', _html_page_context)
    app.connect('config-inited', _config_inited)
    app.add_config_value(
        'git_untracked_check_dependencies', True, rebuild='html')
    app.add_config_value(
        'git_untracked_show_sourcelink', False, rebuild='html')
    return {
        'version': __version__,
        'parallel_read_safe': True,
    }
