import json
from copy import deepcopy

import pytest
import responses

from datarobot import Deployment
from datarobot.enums import MODEL_REPLACEMENT_REASON
from datarobot.utils import from_api
from tests.utils import request_body_to_json


@responses.activate
@pytest.mark.usefixtures('deployment_get_response')
def test_model_replacement_validation(unittest_endpoint, deployment_data):
    deployment_id = deployment_data['id']
    status = 'passing'
    message = 'Model can be used to replace the current model of the deployment.'
    checks = {'targetName': {'status': 'passing', 'message': 'Target name matches.'}}

    url = '{}/deployments/{}/model/validation/'.format(unittest_endpoint, deployment_id)
    responses.add(
        responses.POST,
        url,
        body=json.dumps({'status': status, 'message': message, 'checks': checks}),
        status=200,
        content_type='application/json')

    deployment = Deployment.get(deployment_id)
    response = deployment.validate_replacement_model('5ca3936e0eb05d0155e2b7a5')

    request_body = request_body_to_json(responses.calls[1].request)
    assert request_body['modelId'] == '5ca3936e0eb05d0155e2b7a5'

    assert status == response[0]
    assert message == response[1]
    assert from_api(checks) == response[2]


@responses.activate
def test_model_replacement_submission_pred_int_disabled(unittest_endpoint, deployment_data):
    deployment_id = deployment_data['id']
    new_model_id = '5ca3936e0eb05d0155e2b7a5'
    model_replacement_url = '{}/deployments/{}/model/'.format(unittest_endpoint, deployment_id)
    deployment_url = '{}/deployments/{}/'.format(unittest_endpoint, deployment_id)
    status_url = '{}/status_url'.format(unittest_endpoint)
    settings_url = '{}/deployments/{}/settings/'.format(unittest_endpoint, deployment_id)

    new_deployment_data = deepcopy(deployment_data)
    new_deployment_data['model']['id'] = new_model_id
    responses.add(
        responses.GET,
        deployment_url,
        status=200,
        content_type='application/json',
        body=json.dumps(deployment_data))
    responses.add(
        responses.PATCH,
        model_replacement_url,
        headers={'Location': status_url},
        status=202)
    responses.add(
        responses.GET,
        status_url,
        headers={'Location': deployment_url},
        status=303)
    responses.add(
        responses.GET,
        deployment_url,
        status=200,
        content_type='application/json',
        body=json.dumps(new_deployment_data))
    responses.add(
        responses.GET,
        settings_url,
        status=200,
        content_type='application/json',
        body=json.dumps({'predictionIntervals': {
            'enabled': False,
            'percentiles': []
        }})
    )

    deployment = Deployment.get(deployment_id)
    assert deployment.model['id'] == deployment_data['model']['id']
    deployment.replace_model(new_model_id, MODEL_REPLACEMENT_REASON.DATA_DRIFT)
    assert deployment.model['id'] == new_model_id


@responses.activate
def test_model_replacement_submission_pred_int_enabled(unittest_endpoint, deployment_data):
    deployment_id = deployment_data['id']
    new_model_id = '5ca3936e0eb05d0155e2b7a5'
    model_replacement_url = '{}/deployments/{}/model/'.format(unittest_endpoint, deployment_id)
    deployment_url = '{}/deployments/{}/'.format(unittest_endpoint, deployment_id)
    status_url = '{}/status_url'.format(unittest_endpoint)
    settings_url = '{}/deployments/{}/settings/'.format(unittest_endpoint, deployment_id)

    new_deployment_data = deepcopy(deployment_data)
    new_deployment_data['model']['id'] = new_model_id
    project_id = new_deployment_data['model']['projectId']
    responses.add(
        responses.GET,
        deployment_url,
        status=200,
        content_type='application/json',
        body=json.dumps(deployment_data))
    responses.add(
        responses.PATCH,
        model_replacement_url,
        headers={'Location': status_url},
        status=202)
    responses.add(
        responses.GET,
        status_url,
        headers={'Location': deployment_url},
        status=303)
    responses.add(
        responses.GET,
        deployment_url,
        status=200,
        content_type='application/json',
        body=json.dumps(new_deployment_data))
    responses.add(
        responses.GET,
        settings_url,
        status=200,
        content_type='application/json',
        body=json.dumps({'predictionIntervals': {
            'enabled': True,
            'percentiles': [80]
        }})
    )
    responses.add(
        responses.POST,
        '{}/projects/{}/models/{}/predictionIntervals/'.format(
            unittest_endpoint, project_id, new_model_id
        ),
        status=202,
        headers={'Location': '{}/projects/{}/jobs/1/'.format(unittest_endpoint, project_id)}
    )
    responses.add(
        responses.GET,
        '{}/projects/{}/jobs/1/'.format(unittest_endpoint, project_id),
        status=303,
        content_type='application/json',
        body=json.dumps({
            'status': u'COMPLETED', 'model_id': new_model_id, 'is_blocked': False,
            'url': '{}/projects/{}/jobs/1/'.format(unittest_endpoint, project_id),
            'job_type': 'calculate_prediction_intervals', 'project_id': project_id, 'id': 1
        }),
        headers={'Location': '{}/projects/{}/jobs/1/result/'.format(unittest_endpoint, project_id)}
    )
    responses.add(
        responses.PATCH,
        settings_url,
        headers={'Location': status_url},
        status=202
    )
    responses.add(
        responses.GET,
        status_url,
        headers={'Location': deployment_url},
        status=303
    )

    deployment = Deployment.get(deployment_id)
    assert deployment.model['id'] == deployment_data['model']['id']
    deployment.replace_model(new_model_id, MODEL_REPLACEMENT_REASON.DATA_DRIFT)
    assert deployment.model['id'] == new_model_id
