from flask import url_for
import json

headers = {'content-type': 'application/json'}


def test_endpoint_get_tweets(g, client):

    data = {'tweet': 'test tweet'}
    response = client.post(
        url_for('tweets.create_tweet'),
        headers=headers,
        data=json.dumps(data)
    )
    id1 = response.json['id']
    assert response.status_code == 201

    data_retweet1 = {'name': 'user1', 'id': id1}
    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps(data_retweet1)
    )
    id2 = response.json['id']
    assert response.status_code == 201

    data_retweet2 = {'name': 'unknown', 'id': 0}
    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps(data_retweet2)
    )
    id3 = response.json['id']
    assert response.status_code == 201

    response = client.get(url_for('tweets.get_tweets'))
    assert response.status_code == 200
    result = response.json
    assert len(result) == 2

    response = client.delete(url_for('tweets.delete_tweet', id=id1))
    assert response.status_code == 204

    response = client.delete(url_for('tweets.delete_tweet', id=id2))
    assert response.status_code == 204

    response = client.delete(url_for('tweets.delete_tweet', id=id3))
    assert response.status_code == 204


def test_endpoint_get_tweet(g, client):

    data = {'tweet': 'test tweet'}
    response = client.post(
        url_for('tweets.get_tweets'),
        headers=headers,
        data=json.dumps(data)
    )
    id = response.json['id']
    assert response.status_code == 201

    response = client.get(url_for('tweets.get_tweet', id=id))
    assert response.status_code == 200
    assert response.json['id'] == id
    assert response.json['tweet'] == data['tweet']

    response = client.delete(url_for('tweets.delete_tweet', id=id))
    assert response.status_code == 204

    response = client.get(url_for('tweets.get_tweet', id=707))
    assert response.status_code == 404


def test_create_update_delete_tweet(g, client):

    response = client.post(
        url_for('tweets.create_tweet'),
        headers=headers,
        data=json.dumps({'tweet': 'tweet generated by test'})
    )
    assert response.status_code == 201
    id = response.json['id']

    response = client.post(
        url_for('tweets.create_tweet'),
        headers={'Content-Type': 'bla'},
        data=json.dumps({'tweet': 'tweet generated by test'})
    )
    assert response.status_code == 400

    response = client.post(
        url_for('tweets.create_tweet'),
        headers=headers,
        data=json.dumps({'tweettt': 'tweet generated by test'})
    )
    assert response.status_code == 400

    response = client.put(
        url_for('tweets.update_tweet', id=id),
        headers=headers,
        data=json.dumps({'tweetttt': 'updated tweet'})
    )
    assert response.status_code == 400

    response = client.put(
        url_for('tweets.update_tweet', id=id),
        headers={'Content-Type': 'bla'},
        data=json.dumps({'tweet': 'updated tweet'})
    )
    assert response.status_code == 400

    response = client.put(
        url_for('tweets.update_tweet', id=id),
        headers=headers,
        data=json.dumps({'tweet': 'updated tweet'})
    )
    assert response.status_code == 201

    response = client.delete(url_for('tweets.delete_tweet', id=id))
    assert response.status_code == 204

    response = client.put(
        url_for('tweets.update_tweet', id=707),
        headers=headers,
        data=json.dumps({'tweet': 'updated tweet'})
    )
    assert response.status_code == 404

    response = client.delete(url_for('tweets.update_tweet', id=707))
    assert response.status_code == 404


def test_create_retweet(g, client):

    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps({'name': ''})
    )
    assert response.status_code == 400

    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers={'Content-Type': 'bla'},
        data=json.dumps({'name': 'user1', 'id': 2})
    )
    assert response.status_code == 400

    data = {'tweet': 'tweet to be referenced'}
    response = client.post(
        url_for('tweets.create_tweet'),
        headers=headers,
        data=json.dumps(data)
    )
    assert response.status_code == 201
    id1 = response.json['id']

    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps({'name': 'user1', 'id': id1})
    )
    assert response.status_code == 201
    id2 = response.json['id']

    response = client.get(url_for('tweets.get_tweet', id=id1))
    assert response.status_code == 200
    assert response.json['tweet'] == data['tweet']

    response = client.delete(url_for('tweets.delete_tweet', id=id1))
    assert response.status_code == 204
    response = client.delete(url_for('tweets.delete_tweet', id=id2))
    assert response.status_code == 204


def test_register_unregister(g, client):

    data = {
        'name': 'user5',
        'port': '5004'
    }
    response = client.post(
        url_for('register.register'),
        data=json.dumps(data),
        headers=headers,
        environ_base={'REMOTE_ADDR': '127.0.0.1'}
    )
    assert response.status_code == 200

    response = client.post(
        url_for('register.register'),
        data=json.dumps(data),
        headers=headers,
        environ_base={'REMOTE_ADDR': '127.0.0.1'}
    )
    assert response.status_code == 400

    response = client.post(
        url_for('register.register'),
        data=json.dumps({}),
        headers=headers,
        environ_base={'REMOTE_ADDR': '127.0.0.1'}
    )
    assert response.status_code == 400

    response = client.delete(
        url_for('register.unregister', name=data['name']),
        headers=headers,
        environ_base={'REMOTE_ADDR': '127.0.0.1'}
    )
    assert response.status_code == 200


def test_search_me(g, client):

    ids = fill_db_user1_with_data(g, client)

    response = client.get(url_for('tweets.search_me'))
    assert response.status_code == 200
    assert len(response.json) == 5

    params = {
        'content': 'nice',
        'from_time': '2010',
        'to_time': '2050'
    }
    response = client.get(url_for('tweets.search_me'), query_string=params)
    assert response.status_code == 200
    assert len(response.json) == 2

    params = {
        'content': 'nice',
        'from_time': '2010',
        'to_time': '2012'
    }
    response = client.get(url_for('tweets.search_me'), query_string=params)
    assert response.status_code == 404

    params = {
        'content': 'day'
    }
    response = client.get(url_for('tweets.search_me'), query_string=params)
    assert response.status_code == 200
    assert len(response.json) == 5

    params = {
        'per_page': 2,
        'content': 'day'
    }
    response = client.get(url_for('tweets.search_me'), query_string=params)
    assert response.status_code == 200
    assert len(response.json) == 4
    last_time = response.json[-1]['creation_time']
    params = {
        'per_page': 2,
        'content': 'day',
        'last_creation_time': last_time
    }
    response = client.get(url_for('tweets.search_me'), query_string=params)
    assert response.status_code == 200
    assert len(response.json) == 1

    for i in range(0, len(ids)):
        response = client.delete(url_for('tweets.delete_tweet', id=ids[i]))
        assert response.status_code == 204


def fill_db_user1_with_data(g, client):

    data1 = {'tweet': 'nice day'}
    response = client.post(
        url_for('tweets.create_tweet'),
        headers=headers,
        data=json.dumps(data1)
    )
    id1 = response.json['id']
    assert response.status_code == 201

    data2 = {'tweet': 'beautiful day'}
    response = client.post(
        url_for('tweets.create_tweet'),
        headers=headers,
        data=json.dumps(data2)
    )
    id2 = response.json['id']
    assert response.status_code == 201

    data3 = {'name': 'user1', 'id': id1}
    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps(data3)
    )
    id3 = response.json['id']
    assert response.status_code == 201

    data4 = {'name': 'user1', 'id': id2}
    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps(data4)
    )
    id4 = response.json['id']
    assert response.status_code == 201

    data5 = {'tweet': 'to be deleted'}
    response = client.post(
        url_for('tweets.create_tweet'),
        headers=headers, data=json.dumps(data5)
    )
    id5 = response.json['id']
    assert response.status_code == 201
    response = client.delete(url_for('tweets.delete_tweet', id=id5))
    assert response.status_code == 204

    data6 = {'name': 'user1', 'id': id5}
    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps(data6)
    )
    id6 = response.json['id']
    assert response.status_code == 201

    data7 = {'name': 'user1', 'id': id5}
    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps(data7)
    )
    id7 = response.json['id']
    assert response.status_code == 201

    data8 = {'name': 'user2', 'id': 0}
    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps(data8)
    )
    id8 = response.json['id']
    assert response.status_code == 201

    data9 = {'name': 'user2', 'id': 0}
    response = client.post(
        url_for('tweets.create_re_tweet'),
        headers=headers,
        data=json.dumps(data9)
    )
    id9 = response.json['id']
    assert response.status_code == 201

    data10 = {'tweet': 'joyful day'}
    response = client.post(
        url_for('tweets.create_tweet'),
        headers=headers,
        data=json.dumps(data10)
    )
    id10 = response.json['id']
    assert response.status_code == 201

    ids = [id1, id2, id3, id4, id6, id7, id8, id9, id10]
    return ids


def test_search_all(g, client):

    fill_db_user1_with_data(g, client)

    response = client.get(url_for('tweets.search_all'))
    #results from 3 servers - server user2 and user3 return the same result
    # because there is only one mock of the external server
    assert response.status_code == 200
    assert len(response.json['items']) == 17
    assert response.json['last_creation_time'] == '0'

    params = {
        'name': 'user1',
        'content': 'nice'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 2

    params = {
        'content': 'nice'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 2

    params = {
        'name': 'user2',
        'content': 'nice'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 404

    params = {
        'name': 'user3',
        'content': 'nice'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 404

    params = {
        'content': 'joy'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 3

    params = {
        'content': 'kkkkk'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 404

    params = {
        'content': 'test'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 10

    params = {
        'name': 'user1',
        'content': 'day',
        'per_page': 3,
        'from_time': '2010',
        'to_time': '2050'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 3
    time_of_last_in_page = response.json['last_creation_time']
    params = {
        'name': 'user1',
        'content': 'day',
        'per_page': 3,
        'from_time': '2010',
        'to_time': '2050',
        'last_creation_time': time_of_last_in_page
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 2
    assert '0' == response.json['last_creation_time']

    params = {
        'content': 'day',
        'per_page': 5,
        'from_time': '2010',
        'to_time': '2050'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 5
    time_of_last_in_page = response.json['last_creation_time']
    params = {
        'content': 'day',
        'per_page': 5,
        'from_time': '2010',
        'to_time': '2050',
        'last_creation_time': time_of_last_in_page
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 2
    assert '0' == response.json['last_creation_time']

    params = {
        'content': 'test',
        'per_page': 6,
        'from_time': '2010',
        'to_time': '2050'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 6
    time_of_last_in_page = response.json['last_creation_time']
    params = {
        'content': 'test',
        'per_page': 6,
        'from_time': '2010',
        'to_time': '2050',
        'last_creation_time': time_of_last_in_page
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 4
    assert '0' == response.json['last_creation_time']

    params = {
        'name': 'server',
        'content': 'nice'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 404

    params = {
        'name': 'user1',
        'per_page': 4,
        'from_time': '2010',
        'to_time': '2050'
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 4
    time_of_last_in_page = response.json['last_creation_time']
    params = {
        'name': 'user1',
        'per_page': 4,
        'from_time': '2010',
        'to_time': '2050',
        'last_creation_time': time_of_last_in_page
    }
    response = client.get(url_for('tweets.search_all'), query_string=params)
    assert response.status_code == 200
    assert len(response.json['items']) == 1
    assert '0' == response.json['last_creation_time']
