
import datetime
import time
from typing import Type

import np_logging
import np_session

from np_workflows.experiments import baseclasses, classes
from np_workflows.experiments.baseclasses import Experiment
# we need all experiment classes imported into this namespace
from np_workflows.experiments.classes import *
from np_workflows.workflows.shared import npxc

logger = np_logging.getLogger(__name__)


# mouse & operator ---------------------------------------------------------------------


def select_mouse_and_operator_enter(state_globals) -> None:
    npxc.set(state_globals, operators=[""] + npxc.get_operators())
    state_globals["external"]["mouse"] = "366122"  #! defaults for testing
    # state_globals["external"]["operator"] = 'ben.hardcastle' #! defaults for testing

    # import pdb; pdb.set_trace()
    # state_globals['resources']['workflow']['states'].keys()


def select_mouse_and_operator_input(state_globals) -> None:

    mouse_input = state_globals["external"]["mouse"]
    try:
        npxc.mouse = np_session.lims.MouseInfo(mouse_input)
    except KeyError as exc:
        logger.warning(
            "LIMS | Mouse %r could not be fetched from database: %r", mouse_input, exc
        )
        npxc.mouse = mouse_input
        npxc.is_mouse_in_lims = False

    try:
        project = npxc.mouse.project_name
    except (AttributeError, KeyError):
        project = "NA"
        if npxc.is_mouse_in_lims is None:
            logger.warning(
                "LIMS | Mouse %r could not be fetched from database: %r", mouse_input
            )
        npxc.mouse = mouse_input
        npxc.is_mouse_in_lims = False
    else:
        npxc.is_mouse_in_lims = True
    finally:
        npxc.set(
            state_globals, project=str(project), is_mouse_in_lims=npxc.is_mouse_in_lims
        )

    operator_input = state_globals["external"]["operator"]
    try:
        npxc.operator = np_session.lims.UserInfo(operator_input)
    except KeyError as exc:
        logger.warning(
            "LIMS | Operator %r could not be fetched from database: %r",
            operator_input,
            exc,
        )
        npxc.operator = operator_input

    status_message = f'Mouse {"is" if npxc.is_mouse_in_lims else "is not"} in lims'
    transition_result = (
        False if not npxc.is_mouse_in_lims else True
    )  # None isn't allowed in s_g['external']
    npxc.set(
        state_globals,
        status_message=status_message,
        transition_result=transition_result,
    )


# experiment ---------------------------------------------------------------------------


def select_experiment_enter(state_globals) -> None:
    experiments = npxc.get_experiments(with_lims=bool(npxc.is_mouse_in_lims))
    if not experiments:
        alert = True
        msg_text = "No experiments found"
        npxc.set(state_globals, alert=alert, msg_text=msg_text)
    npxc.set(state_globals, experiments=[""] + experiments)


def select_experiment_input(state_globals) -> None:
    "Create Experiment instance and configure services"

    experiment_class: Type[Experiment] = eval(npxc.get(state_globals, "experiment"))

    if issubclass(experiment_class, baseclasses.WithLims):
        npxc.experiment = experiment_class(
            *npxc.get(state_globals, "mouse", "operator"),
            lims_session_id=int(npxc.session) if npxc.session else None,
        )
    else:
        npxc.experiment = experiment_class(npxc.mouse)

    if not isinstance(npxc.experiment, Experiment):
        raise ValueError(
            f"Experiment {npxc.experiment!r} was not converted to a valid Experiment class"
        )

    npxc.experiment.state_globals = state_globals
    npxc.experiment.initialize_services()
