#!/usr/bin/env python3

import argparse
import json
import os
import requests
import requests.adapters
import requests.exceptions
import urllib3.util.retry

EXAMPLE_SIMULATIONS_RUNS_FILENAME = os.path.join(os.path.dirname(__file__),
                                                 '..', 'apps', 'dispatch', 'src', 'app', 'components',
                                                 'simulations', 'browse', 'example-simulations.{}.json')


def get_api_endpoint(biosimulations_api):
    """ Get the endpoint for checkin gthe status of each simulation run

    Args:
        biosimulations_api (:obj:`str`): API to use to check the status of each run
            (``dev``, ``org``, or ``local``)

    Returns:
        :obj:`str`: endpoint for checkin gthe status of each simulation run
    """
    if biosimulations_api == 'local':
        return 'http://localhost:3333'

    return 'https://api.biosimulations.{}'.format(biosimulations_api)


def get_failed_runs(examples_api, biosimulations_api):
    """ Get a list of any example simulation runs that didn't succeed

    Args:
        examples_api (:obj:`str`): example set to test (``dev`` or ``org``)
        biosimulations_api (:obj:`str`): API to use to check the status of each run
            (``dev``, ``org``, or ``local``)

    Returns:
        :obj:`list` of :obj:`str`: ids and names of failed simulation runs
    """

    # get name of file with runs
    filename = EXAMPLE_SIMULATIONS_RUNS_FILENAME.format(examples_api)

    # read simulation runs
    with open(filename, 'r') as file:
        runs = json.load(file)

    # check the status of each run
    endpoint = get_api_endpoint(biosimulations_api)
    failures = []
    for run in runs:
        # check status
        try:
            response = requests.get('{}/runs/{}'.format(endpoint, run['id']))
            response.raise_for_status()
            status = response.json()['status']
            if status != 'SUCCEEDED':
                failures.append('{}: {}: {}: {}'.format(examples_api, run['id'], status, run['name']))
                continue
        except requests.exceptions.RequestException:
            failures.append('{}: status check: {}'.format(examples_api, run['id'], run['name']))
            continue

        # check COMBINE/OMEX archive
        try:
            response = requests.get('{}/runs/{}/download'.format(endpoint, run['id']))
            response.raise_for_status()
        except requests.exceptions.RequestException:
            failures.append('{}: COMBINE download: {}'.format(examples_api, run['id'], run['name']))
            continue

        # check files
        try:
            response = requests.get('{}/files/{}'.format(endpoint, run['id']))
            response.raise_for_status()
        except requests.exceptions.RequestException:
            failures.append('{}: files: {}'.format(examples_api, run['id'], run['name']))
            continue

        # check SED-ML specifications
        try:
            response = requests.get('{}/specifications/{}'.format(endpoint, run['id']))
            response.raise_for_status()
        except requests.exceptions.RequestException:
            failures.append('{}: specifications: {}'.format(examples_api, run['id'], run['name']))
            continue

        # check metadata
        try:
            response = requests.get('{}/metadata/{}'.format(endpoint, run['id']))
            response.raise_for_status()
        except requests.exceptions.RequestException:
            failures.append('{}: metadata: {}'.format(examples_api, run['id'], run['name']))
            continue

        # check results
        retries = urllib3.util.retry.Retry(total=10, backoff_factor=10)
        retry_session = requests.Session()
        retry_session.mount(endpoint, requests.adapters.HTTPAdapter(max_retries=retries))

        try:
            response = retry_session.get('{}/results/{}?includeData=false'.format(endpoint, run['id']))
            response.raise_for_status()
        except requests.exceptions.RequestException:
            failures.append('{}: results: {}'.format(examples_api, run['id'], run['name']))
            continue

        try:
            response = requests.get('{}/results/{}/download'.format(endpoint, run['id']))
            response.raise_for_status()
        except requests.exceptions.RequestException:
            failures.append('{}: results download: {}'.format(examples_api, run['id'], run['name']))
            continue

        # check logs
        try:
            response = requests.get('{}/logs/{}'.format(endpoint, run['id']))
            response.raise_for_status()
        except requests.exceptions.RequestException:
            failures.append('{}: logs: {}'.format(examples_api, run['id'], run['name']))
            continue

    # return list of failed runs
    return failures


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Check that all of the example simulation runs succeeded.'
    )
    parser.add_argument(
        '--runbiosimulations-api',
        type=str,
        default='dev',
        help='BioSimulations API which for projects should be checked (`dev`, `org`, `local`). Default: `dev`.'
    )
    args = parser.parse_args()

    examples_api = args.runbiosimulations_api
    if examples_api == 'local':
        examples_api = 'dev'
    failures = get_failed_runs(examples_api, args.runbiosimulations_api)

    if failures:
        msg = 'The following example simulation runs did not succeed:\n  {}'.format('\n  '.join(failures))
        raise SystemExit(msg)
    else:
        print('All example simulation runs succeeded!')
