#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
A command-line program that runs all ObsPy tests.

All tests in ObsPy are located in the tests directory of each specific
module.

A few important command line arguments:
    --help : Print help message an exit.
    --no-report, --report : Do not ask and automatically (not) submit report
            to ObsPys' report server.
    --cov obspy: Calculate and display test coverage.
    --network : Only run network tests (requires an internet connection).
    --all : Run both network and non-network tests.
    --keep-images : Store all images generated by tests in obspy's directory.

Also note, the test runner uses pytest under the hood so any pytest command
line argument is also accepted.

.. rubric:: Examples

(1) Run all local tests (ignoring tests requiring a network connection) on
    command line::
        $ obspy-runtests
(2) Run all tests on command line (including network tests)::
        $ obspy-runtests --all
(3) Run tests of module :mod:`obspy.io.mseed`::
        $ obspy-runtests io/mseed
(4) Run tests of multiple modules, e.g. :mod:`obspy.io.wav` and
    :mod:`obspy.io.sac`::
        $ obspy-runtests io/wav obspy/io/sac
(5) Run a specific test case::
        $ obspy-runtests core/tests/test_stats.py::TestStats::test_init
(6) Run tests and print a coverage report to screen including missed lines:
        $ obspy-runtests --cov obspy --cov-report term-missing
(7) Save the image outputs of the testsuite, called 'obspy_image_tests':
        $ obspy-runtests --keep-images
(8) Run the test suite, drop into a pdb debugging session for each failure:
        $ obspy-runtests --pdb

:copyright:
    The ObsPy Development Team (devs@obspy.org)
:license:
    GNU Lesser General Public License, Version 3
    (https://www.gnu.org/copyleft/lesser.html)
"""
import contextlib
import os
import sys
from pathlib import Path


# URL to upload json report
REPORT_URL = "tests.obspy.org"


@contextlib.contextmanager
def change_directory(path):
    """
    A context manager to change directory to target path.

    :param path: The path to change to.
    :type path: A string or pathlib Path.
    """
    origin = Path().absolute()
    try:
        os.chdir(path)
        yield
    finally:
        os.chdir(origin)


def main():
    """
    Entry point for setup.py.
    Wrapper for a profiler if requested otherwise just call run() directly.
    If profiling is enabled we disable interactivity as it would wait for user
    input and influence the statistics. However the -r option still works.
    """
    if '-h' in sys.argv or '--help' in sys.argv:
        print(__doc__)
        sys.exit(0)
    try:
        import pytest
        from pytest_jsonreport.plugin import JSONReport
    except ImportError:
        msg = ("\nObsPy's test suite uses pytest and pytest-json-report. "
               "Please install these packages before using obspy-runtests. "
               "Example with pip:\n"
               "\t$ pip install pytest pytest-json-report\n\n"
               "Additional optional test requirements can be used and "
               "installed with:\n"
               "\t$ pip install obspy[tests]\n")
        sys.exit(msg)
    # hack to get rid of internal pytest warning, see
    # https://github.com/pytest-dev/pytest-cov/issues/148
    import pytest_jsonreport
    pytest_jsonreport.__doc__ = 'PYTEST_DONT_REWRITE'
    # Cd into ObsPy's directory and run tests.
    with change_directory(Path(__file__).parent.parent):
        plugin = JSONReport()
        status = pytest.main(plugins=[plugin])
    # Upload test report if tests were successfully run.
    # See https://docs.pytest.org/en/latest/reference/exit-codes.html
    if int(status) < 2:
        report = (True if '--report' in sys.argv else
                  False if '--no-report' in sys.argv else None)
        upload_json_report(report=report, data=plugin.report)
    sys.exit(status)


def upload_json_report(report=None, data=None):
    """Upload the json report to ObsPy test server."""
    import requests
    if report is None:
        msg = f"Do you want to report this to {REPORT_URL} ? [n]: "
        answer = input(msg).lower()
        report = 'y' in answer
    if report:
        # only include unique warnings.
        data.setdefault('warnings', [])
        data['warnings'] = [
            dict(t) for t in {tuple(d.items()) for d in data['warnings']}
        ]
        response = requests.post(f"https://{REPORT_URL}/post/v2/", json=data)
        # get the response
        if response.status_code == 200:
            report_url = response.json().get('url', REPORT_URL)
            print('Your test results have been reported and are available at: '
                  '{}\nThank you!'.format(report_url))
        # handle errors
        else:
            print(f"Error: Could not sent a test report to {REPORT_URL}.")
            print(response.reason)


if __name__ == "__main__":
    main()
