import logging

from opentrons.protocol_api.contexts import ProtocolContext
from opentrons.protocols.execution.execute_python import run_python
from opentrons.protocols.execution.json_dispatchers import (
    pipette_command_map, temperature_module_command_map,
    magnetic_module_command_map, thermocycler_module_command_map)
from opentrons.protocols.execution import execute_json_v4, execute_json_v3

from opentrons.protocols.types import (PythonProtocol, Protocol, APIVersion)

MODULE_LOG = logging.getLogger(__name__)


def run_protocol(protocol: Protocol,
                 context: ProtocolContext):
    """ Run a protocol.

    :param protocol: The :py:class:`.protocols.types.Protocol` to execute
    :param context: The context to use.
    """
    if isinstance(protocol, PythonProtocol):
        if protocol.api_level >= APIVersion(2, 0):
            run_python(protocol, context)
        else:
            raise RuntimeError(
                f'Unsupported python API version: {protocol.api_level}'
            )
    else:
        if protocol.contents['schemaVersion'] == 3:
            ins = execute_json_v3.load_pipettes_from_json(
                context, protocol.contents)
            lw = execute_json_v3.load_labware_from_json_defs(
                context, protocol.contents)
            execute_json_v3.dispatch_json(context, protocol.contents, ins, lw)
        elif protocol.contents['schemaVersion'] in [4, 5]:
            # reuse the v3 fns for loading labware and pipettes
            # b/c the v4 protocol has no changes for these keys
            ins = execute_json_v3.load_pipettes_from_json(
                context, protocol.contents)

            modules = execute_json_v4.load_modules_from_json(
                context, protocol.contents)

            lw = execute_json_v4.load_labware_from_json_defs(
                context, protocol.contents, modules)
            execute_json_v4.dispatch_json(
                context, protocol.contents, ins, lw, modules,
                pipette_command_map, magnetic_module_command_map,
                temperature_module_command_map,
                thermocycler_module_command_map)
        else:
            raise RuntimeError(
                f'Unsupported JSON protocol schema: {protocol.schema_version}')
