"""Adapter for the supplied acknowledgment-only FinBot interface. No live orders."""
import argparse
import json
import ssl
import urllib.error
import urllib.request

BASE_URL = 'https://6fdb1a15-b48a-49f7-833a-dcec3b7f7ff1.cfargotunnel.com'
MAX_RESPONSE_BYTES = 65536


class ProtocolError(ValueError):
    pass


class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, *args, **kwargs):
        return None


def unique_fields(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ProtocolError('Duplicate JSON field')
        result[key] = value
    return result


def parse_response(raw, content_type, method):
    if method not in ('GET', 'POST'):
        raise ProtocolError('Unsupported interface method')
    if len(raw) > MAX_RESPONSE_BYTES:
        raise ProtocolError('Response exceeds size limit')
    if content_type.split(';', 1)[0].strip().lower() != 'application/json':
        raise ProtocolError('Expected application/json')
    try:
        data = json.loads(raw, object_pairs_hook=unique_fields,
                          parse_constant=lambda _: (_ for _ in ()).throw(ProtocolError('Nonfinite JSON')))
    except (ValueError, UnicodeError):
        raise ProtocolError('Invalid JSON response') from None
    if not isinstance(data, dict):
        raise ProtocolError('Expected JSON object')
    expected = 'PACKAGE_RECEIVED_ALERT' if method == 'GET' else 'VERIFIED_AND_COMMITTED'
    if data.get('status') != expected:
        raise ProtocolError('Expected acknowledgment status absent')
    if method == 'POST' and data.get('order_id') != 'MOCK_UPSTREAM_EXECUTION_ID':
        raise ProtocolError('Unexpected execution identifier; simulation loop stopped')
    return {'interface_status': expected,
            'interpretation': 'RECEPTION_ACKNOWLEDGED' if method == 'GET' else 'MOCK_RESPONSE_RECEIVED',
            'exchange_authentication_verified': False,
            'broker_order_verified': False, 'ledger_commit_verified': False,
            'live_order_submission_enabled': False}


def check_connection():
    """One bounded GET to the pinned root. No tokens, POSTs, redirects or retries."""
    opener = urllib.request.build_opener(
        NoRedirect(), urllib.request.HTTPSHandler(context=ssl.create_default_context()))
    request = urllib.request.Request(BASE_URL, method='GET',
                                     headers={'Accept': 'application/json', 'Cache-Control': 'no-cache'})
    report = {'target': BASE_URL, 'credentials_sent': False, 'redirects_followed': False,
              'live_order_submission_enabled': False, 'orders_submitted': 0}
    try:
        with opener.open(request, timeout=15) as response:
            report['http_status'] = response.status
            report['content_type'] = response.headers.get('Content-Type', '')
            if response.status != 200:
                raise ProtocolError('Expected HTTP 200')
            report.update(parse_response(response.read(MAX_RESPONSE_BYTES + 1), report['content_type'], 'GET'))
            report['check'] = 'INTERFACE_ACKNOWLEDGED'
    except urllib.error.HTTPError as error:
        report.update(check='HTTP_REJECTED', http_status=error.code)
        error.close()
    except (urllib.error.URLError, OSError):
        report['check'] = 'CONNECTION_FAILED'
    except ProtocolError as error:
        report.update(check='PROTOCOL_REJECTED', reason=str(error))
    return report


def submit_order(*args, **kwargs):
    raise ProtocolError('Live and paper order submission are disabled in this adapter')


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--check', action='store_true', help='Send one unauthenticated root GET')
    args = parser.parse_args()
    if not args.check:
        parser.print_help()
        return 0
    result = check_connection()
    print(json.dumps(result, indent=2))
    return 0 if result['check'] == 'INTERFACE_ACKNOWLEDGED' else 1


if __name__ == '__main__':
    raise SystemExit(main())
