import os
import shutil

import pytest

from ramp_database.model import Model
from ramp_database.testing import add_users
from ramp_database.tools.team import sign_up_team
from ramp_database.tools.submission import get_submissions
from ramp_database.tools.submission import submit_starting_kits
from ramp_database.utils import session_scope
from ramp_database.utils import setup_db

from ramp_database.tools.event import get_problem

from ramp_engine.local import CondaEnvWorker
from ramp_engine.dispatcher import Dispatcher

from ramp_utils import generate_ramp_config
from ramp_utils import read_config
from ramp_utils.testing import database_config_template
from ramp_utils.testing import ramp_config_template

from ramp_utils.deploy import deploy_ramp_event


@pytest.fixture
def session_scope_function(database_connection):
    database_config = read_config(database_config_template())
    ramp_config = read_config(ramp_config_template())
    try:
        yield
    finally:
        # FIXME: we are recreating the deployment directory but it should be
        # replaced by an temporary creation of folder.
        deployment_dir = os.path.commonpath(
            [ramp_config['ramp']['kit_dir'], ramp_config['ramp']['data_dir']]
        )
        shutil.rmtree(deployment_dir, ignore_errors=True)
        db, _ = setup_db(database_config['sqlalchemy'])
        Model.metadata.drop_all(db)


def test_deploy_ramp_event_options(session_scope_function):
    database_config = read_config(database_config_template())
    ramp_config = generate_ramp_config(read_config(ramp_config_template()))
    deploy_ramp_event(database_config_template(), ramp_config_template())
    # deploy again by forcing the deployment
    deploy_ramp_event(
        database_config_template(), ramp_config_template(), force=True
    )
    # do not deploy the kit to trigger the error in the problem with we don't
    # force the deployment
    msg_err = 'The RAMP problem already exists in the database.'
    with pytest.raises(ValueError, match=msg_err):
        with session_scope(database_config['sqlalchemy']) as session:
            # if one of the ramp-kit or ramp-data folders changed
            problem = get_problem(session, 'iris')
            problem.path_ramp_kit = problem.path_ramp_kit + '_xxx'
            session.commit()
            deploy_ramp_event(
                database_config_template(), ramp_config_template(),
                setup_ramp_repo=False, force=False
            )

            problem = get_problem(session, 'iris')
            problem.path_ramp_kit = ramp_config['ramp_kit_dir']
            problem.path_ramp_data = problem.path_ramp_data + '_xxx'
            session.commit()
            deploy_ramp_event(
                database_config_template(), ramp_config_template(),
                setup_ramp_repo=False, force=False
            )

    msg_err = 'Attempting to overwrite existing event'
    with pytest.raises(ValueError, match=msg_err):
        with session_scope(database_config['sqlalchemy']) as session:
            # if the problem is the same, then the event should be overwritten
            problem = get_problem(session, 'iris')
            problem.path_ramp_kit = ramp_config['ramp_kit_dir']
            problem.path_ramp_data = ramp_config['ramp_data_dir']
            session.commit()
            deploy_ramp_event(
                database_config_template(), ramp_config_template(),
                setup_ramp_repo=False, force=False
            )


def test_deploy_ramp_event(session_scope_function):
    database_config = read_config(database_config_template())
    event_config_filename = ramp_config_template()
    event_config = read_config(event_config_filename)
    ramp_config = generate_ramp_config(event_config)
    deploy_ramp_event(database_config_template(), ramp_config_template())

    # simulate that we add users and sign-up for the event and that they
    # submitted the starting kit
    with session_scope(database_config['sqlalchemy']) as session:
        add_users(session)
        sign_up_team(session, ramp_config['event_name'], 'test_user')
        submit_starting_kits(session, ramp_config['event_name'], 'test_user',
                             ramp_config['ramp_kit_submissions_dir'])

    # run the dispatcher on the event which are in the dataset
    dispatcher = Dispatcher(config=database_config,
                            event_config=event_config,
                            worker=CondaEnvWorker,
                            n_workers=-1,
                            hunger_policy='exit')
    dispatcher.launch()

    # the iris kit contain a submission which should fail for a user
    with session_scope(database_config['sqlalchemy']) as session:
        submission = get_submissions(
            session, event_config['ramp']['event_name'], 'training_error'
        )
        assert len(submission) == 1
