import io
import time

import todoist


def test_stats_get(api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    response = api.completed.get_stats()
    assert 'days_items' in response
    assert 'week_items' in response
    assert 'karma_trend' in response
    assert 'karma_last_update' in response


def test_user_update(api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()
    date_format = api.state['user']['date_format']
    date_format_new = 1 - date_format
    api.user.update(date_format=date_format_new)
    api.commit()
    assert date_format_new == api.state['user']['date_format']
    api.user.update_goals(vacation_mode=1)
    api.commit()
    api.user.update_goals(vacation_mode=0)
    api.commit()


def test_user_settings_update(api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()
    reminder_email = api.state['user_settings']['reminder_email']
    if reminder_email:
        reminder_email = False
    else:
        reminder_email = True
    api.user_settings.update(reminder_email=reminder_email)
    api.commit()
    assert reminder_email == api.state['user_settings']['reminder_email']


def test_project_add(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    response = api.commit()
    assert response['projects'][0]['name'] == 'Project1'
    assert 'Project1' in [p['name'] for p in api.state['projects']]
    assert api.projects.get_by_id(project1['id']) == project1

    project1.delete()
    api.commit()


def test_project_delete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    project1.delete()
    response = api.commit()
    assert response['projects'][0]['id'] == project1['id']
    assert response['projects'][0]['is_deleted'] == 1
    assert 'Project1' not in [p['name'] for p in api.state['projects']]


def test_project_update(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    project1.update(name='UpdatedProject1')
    response = api.commit()
    assert response['projects'][0]['name'] == 'UpdatedProject1'
    assert 'UpdatedProject1' in [p['name'] for p in api.state['projects']]
    assert api.projects.get_by_id(project1['id']) == project1

    project1.delete()
    api.commit()


def test_project_archive(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    project1.archive()
    response = api.commit()
    assert response['projects'][0]['name'] == 'Project1'
    assert response['projects'][0]['is_archived'] == 1
    assert 'Project1' in [p['name'] for p in api.state['projects']]
    assert 1 in [
        p['is_archived'] for p in api.state['projects']
        if p['id'] == project1['id']
    ]

    project1.delete()
    api.commit()


def test_project_unarchive(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    project1.archive()
    api.commit()

    project1.unarchive()
    response = api.commit()
    assert response['projects'][0]['name'] == 'Project1'
    assert response['projects'][0]['is_archived'] == 0
    assert 0 in [
        p['is_archived'] for p in api.state['projects']
        if p['id'] == project1['id']
    ]

    project1.delete()
    api.commit()


def test_project_move_to_parent(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    project2 = api.projects.add('Project2')
    api.commit()

    project2.move(project1['id'])
    response = api.commit()
    assert response['projects'][0]['name'] == 'Project2'
    assert response['projects'][0]['parent_id'] == project1['id']
    assert project1['id'] in [
        i['parent_id'] for i in api.state['projects'] if i['id'] == project2['id']
    ]

    project2.delete()
    api.commit()
    project1.delete()
    api.commit()


def test_project_reorder(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    project2 = api.projects.add('Project2')
    api.commit()

    api.projects.reorder(projects=[
        {'id': project1['id'], 'child_order': 2},
        {'id': project2['id'], 'child_order': 1},
    ])
    response = api.commit()
    for project in response['projects']:
        if project['id'] == project1['id']:
            assert project['child_order'] == 2
        if project['id'] == project2['id']:
            assert project['child_order'] == 1
    assert 2 in [
        p['child_order'] for p in api.state['projects']
        if p['id'] == project1['id']
    ]
    assert 1 in [
        p['child_order'] for p in api.state['projects']
        if p['id'] == project2['id']
    ]

    project1.delete()
    api.commit()
    project2.delete()
    api.commit()


def test_item_add(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    response = api.add_item('Item1')
    assert response['content'] == 'Item1'
    api.sync()
    assert 'Item1' in [i['content'] for i in api.state['items']]
    item1 = [i for i in api.state['items'] if i['content'] == 'Item1'][0]
    assert api.items.get_by_id(item1['id']) == item1

    item1.delete()
    api.commit()


def test_item_delete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.sync()

    item1.delete()
    response = api.commit()
    assert response['items'][0]['id'] == item1['id']
    assert response['items'][0]['is_deleted'] == 1
    assert 'Item1' not in [i['content'] for i in api.state['items']]


def test_item_update(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()

    item1.update(content='UpdatedItem1')
    response = api.commit()
    assert response['items'][0]['content'] == 'UpdatedItem1'
    assert 'UpdatedItem1' in [i['content'] for i in api.state['items']]
    assert api.items.get_by_id(item1['id']) == item1

    item1.delete()
    api.commit()


def test_item_complete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    item2 = api.items.add('Item2', parent_id=item1['id'])
    api.commit()

    item2.complete()
    response = api.commit()
    assert response['items'][0]['content'] == 'Item2'
    assert response['items'][0]['checked'] == 1
    assert 1 in [
        i['checked'] for i in api.state['items'] if i['id'] == item2['id']
    ]

    item1.delete()
    api.commit()
    item2.delete()
    api.commit()


def test_item_uncomplete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    item2 = api.items.add('Item2', parent_id=item1['id'])
    api.commit()
    item2.complete()
    api.commit()

    item2.uncomplete()
    response = api.commit()
    assert response['items'][0]['content'] == 'Item2'
    assert response['items'][0]['checked'] == 0
    assert 0 in [
        i['checked'] for i in api.state['items'] if i['id'] == item1['id']
    ]

    item1.delete()
    api.commit()
    item2.delete()
    api.commit()


def test_item_archive(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    item2 = api.items.add('Item2', parent_id=item1['id'])
    api.commit()
    item2.complete()
    api.commit()

    item2.archive()
    response = api.commit()
    assert response['items'][0]['content'] == 'Item2'
    assert response['items'][0]['in_history'] == 1
    assert 1 in [
        i['in_history'] for i in api.state['items'] if i['id'] == item2['id']
    ]

    item1.delete()
    api.commit()
    item2.delete()
    api.commit()


def test_item_unarchive(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    item2 = api.items.add('Item2', parent_id=item1['id'])
    api.commit()
    item2.complete()
    api.commit()
    item2.archive()
    api.commit()

    item2.unarchive()
    response = api.commit()
    assert response['items'][0]['content'] == 'Item2'
    assert response['items'][0]['in_history'] == 0
    assert 0 in [
        i['in_history'] for i in api.state['items'] if i['id'] == item2['id']
    ]

    item1.delete()
    api.commit()
    item2.delete()
    api.commit()


def test_item_move_to_project(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    project1 = api.projects.add('Project1')
    api.commit()

    item1.move(project_id=project1['id'])
    response = api.commit()
    assert response['items'][0]['content'] == 'Item1'
    assert response['items'][0]['project_id'] == project1['id']
    assert project1['id'] in [
        i['project_id'] for i in api.state['items'] if i['id'] == item1['id']
    ]

    item1.delete()
    api.commit()
    project1.delete()
    api.commit()


def test_item_move_to_parent(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    item2 = api.items.add('Item2')
    api.commit()

    item2.move(parent_id=item1['id'])
    response = api.commit()
    assert response['items'][0]['content'] == 'Item2'
    assert response['items'][0]['parent_id'] == item1['id']
    assert item1['id'] in [
        i['parent_id'] for i in api.state['items'] if i['id'] == item2['id']
    ]

    item1.delete()
    api.commit()
    item2.delete()
    api.commit()


def test_item_update_date_complete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1', due={'string': 'every day'})
    api.commit()

    now = time.time()
    tomorrow = time.gmtime(now + 24 * 3600)
    new_date_utc = time.strftime("%Y-%m-%dT%H:%M:%SZ", tomorrow)
    due = {
        'date': new_date_utc,
        'string': 'every day',
    }
    api.items.update_date_complete(item1['id'], due=due)
    response = api.commit()
    assert response['items'][0]['due']['string'] == 'every day'
    assert 'every day' in [
        i['due']['string'] for i in api.state['items'] if i['id'] == item1['id']
    ]

    item1.delete()
    api.commit()


def test_item_reorder(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    item2 = api.items.add('Item2')
    api.commit()

    api.items.reorder(items=[
        {'id': item1['id'], 'child_order': 2},
        {'id': item2['id'], 'child_order': 1},
    ])
    response = api.commit()
    for item in response['items']:
        if item['id'] == item1['id']:
            assert item['child_order'] == 2
        if item['id'] == item2['id']:
            assert item['child_order'] == 1
    assert 2 in [
        p['child_order'] for p in api.state['items']
        if p['id'] == item1['id']
    ]
    assert 1 in [
        p['child_order'] for p in api.state['items']
        if p['id'] == item2['id']
    ]

    item1.delete()
    api.commit()
    item2.delete()
    api.commit()


def test_item_update_day_orders(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    item2 = api.items.add('Item2')
    api.commit()

    api.items.update_day_orders({item1['id']: 1, item2['id']: 2})
    response = api.commit()
    for item in response['items']:
        if item['id'] == item1['id']:
            assert item['day_order'] == 1
        if item['id'] == item2['id']:
            assert item['day_order'] == 2
    assert 1 == api.state['day_orders'][str(item1['id'])]
    assert 2 == api.state['day_orders'][str(item2['id'])]

    item1.delete()
    api.commit()

    item2.delete()
    api.commit()


def test_label_add(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    label1 = api.labels.add('Label1')
    response = api.commit()
    assert response['labels'][0]['name'] == 'Label1'
    assert 'Label1' in [l['name'] for l in api.state['labels']]
    assert api.labels.get_by_id(label1['id']) == label1

    label1.delete()
    api.commit()


def test_label_delete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    label1 = api.labels.add('Label1')
    api.commit()

    label1.delete()
    response = api.commit()
    assert response['labels'][0]['id'] == label1['id']
    assert response['labels'][0]['is_deleted'] == 1
    assert 'UpdatedLabel1' not in [l['name'] for l in api.state['labels']]


def test_label_update(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    label1 = api.labels.add('Label1')
    api.commit()

    label1.update(name='UpdatedLabel1')
    response = api.commit()
    assert response['labels'][0]['name'] == 'UpdatedLabel1'
    assert 'UpdatedLabel1' in [l['name'] for l in api.state['labels']]
    assert api.labels.get_by_id(label1['id']) == label1

    label1.delete()
    api.commit()


def test_label_update_orders(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    label1 = api.labels.add('Label1')
    api.commit()
    label2 = api.labels.add('Label2')
    api.commit()

    api.labels.update_orders({label1['id']: 1, label2['id']: 2})
    response = api.commit()
    for label in response['labels']:
        if label['id'] == label1['id']:
            assert label['item_order'] == 1
        if label['id'] == label2['id']:
            assert label['item_order'] == 2
    assert 1 in [
        l['item_order'] for l in api.state['labels'] if l['id'] == label1['id']
    ]
    assert 2 in [
        l['item_order'] for l in api.state['labels'] if l['id'] == label2['id']
    ]

    label1.delete()
    api.commit()
    label2.delete()
    api.commit()


def test_note_add(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()

    note1 = api.notes.add(item1['id'], 'Note1')
    response = api.commit()
    assert response['notes'][0]['content'] == 'Note1'
    assert 'Note1' in [n['content'] for n in api.state['notes']]
    assert api.notes.get_by_id(note1['id']) == note1

    note1.delete()
    api.commit()
    item1.delete()
    api.commit()


def test_note_delete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    note1 = api.notes.add(item1['id'], 'Note1')
    api.commit()

    note1.delete()
    response = api.commit()
    assert response['notes'][0]['id'] == note1['id']
    assert response['notes'][0]['is_deleted'] == 1
    assert 'UpdatedNote1' not in [n['content'] for n in api.state['notes']]

    note1.delete()
    api.commit()
    item1.delete()
    api.commit()


def test_note_update(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1')
    api.commit()
    note1 = api.notes.add(item1['id'], 'Note1')
    api.commit()

    note1.update(content='UpdatedNote1')
    response = api.commit()
    assert response['notes'][0]['content'] == 'UpdatedNote1'
    assert 'UpdatedNote1' in [n['content'] for n in api.state['notes']]
    assert api.notes.get_by_id(note1['id']) == note1

    note1.delete()
    api.commit()
    item1.delete()
    api.commit()


def test_projectnote_add(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    note1 = api.project_notes.add(project1['id'], 'Note1')
    response = api.commit()
    assert response['project_notes'][0]['content'] == 'Note1'
    assert 'Note1' in [n['content'] for n in api.state['project_notes']]
    assert api.project_notes.get_by_id(note1['id']) == note1

    note1.delete()
    api.commit()
    project1.delete()
    api.commit()


def test_projectnote_delete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()
    note1 = api.project_notes.add(project1['id'], 'Note1')
    api.commit()

    note1.delete()
    response = api.commit()
    assert response['project_notes'][0]['id'] == note1['id']
    assert response['project_notes'][0]['is_deleted'] == 1
    assert 'UpdatedNote1' not in [
        n['content'] for n in api.state['project_notes']
    ]

    project1.delete()
    api.commit()


def test_projectnote_update(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    project1 = api.projects.add('Project1')
    api.commit()
    note1 = api.project_notes.add(project1['id'], 'Note1')
    api.commit()

    note1.update(content='UpdatedNote1')
    response = api.commit()
    assert response['project_notes'][0]['content'] == 'UpdatedNote1'
    assert 'UpdatedNote1' in [n['content'] for n in api.state['project_notes']]
    assert api.project_notes.get_by_id(note1['id']) == note1

    note1.delete()
    api.commit()
    project1.delete()
    api.commit()


def test_filter_add(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    filter1 = api.filters.add('Filter1', 'no due date')
    response = api.commit()
    assert response['filters'][0]['name'] == 'Filter1'
    assert 'Filter1' in [f['name'] for f in api.state['filters']]
    assert api.filters.get_by_id(filter1['id']) == filter1

    filter1.delete()
    api.commit()


def test_filter_delete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    filter1 = api.filters.add('Filter1', 'no due date')
    api.commit()

    filter1.delete()
    response = api.commit()
    assert response['filters'][0]['id'] == filter1['id']
    assert response['filters'][0]['is_deleted'] == 1
    assert 'Filter1' not in [p['name'] for p in api.state['filters']]


def test_filter_update(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    filter1 = api.filters.add('Filter1', 'no due date')
    api.commit()

    filter1.update(name='UpdatedFilter1')
    response = api.commit()
    assert response['filters'][0]['name'] == 'UpdatedFilter1'
    assert 'UpdatedFilter1' in [f['name'] for f in api.state['filters']]
    assert api.filters.get_by_id(filter1['id']) == filter1

    filter1.delete()
    api.commit()


def test_filter_update_orders(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    filter1 = api.filters.add('Filter1', 'no due date')
    api.commit()

    filter2 = api.filters.add('Filter2', 'today')
    api.commit()

    api.filters.update_orders({filter1['id']: 2, filter2['id']: 1})
    response = api.commit()
    for filter in response['filters']:
        if filter['id'] == filter1['id']:
            assert filter['item_order'] == 2
        if filter['id'] == filter2['id']:
            assert filter['item_order'] == 1
    assert 2 in [
        f['item_order'] for f in api.state['filters']
        if f['id'] == filter1['id']
    ]
    assert 1 in [
        f['item_order'] for f in api.state['filters']
        if f['id'] == filter2['id']
    ]

    filter1.delete()
    api.commit()
    filter2.delete()
    api.commit()


def test_reminder_relative_add(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1', due={'string': 'tomorrow 5pm'})
    api.commit()

    reminder1 = api.reminders.add(item1['id'], minute_offset=30)
    response = api.commit()
    assert response['reminders'][0]['minute_offset'] == 30
    assert reminder1['id'] in [p['id'] for p in api.state['reminders']]
    assert api.reminders.get_by_id(reminder1['id']) == reminder1

    reminder1.delete()
    api.commit()
    item1.delete()
    api.commit()


def test_reminder_relative_delete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1', due={'string': 'tomorrow 5pm'})
    api.commit()
    reminder1 = api.reminders.add(item1['id'], minute_offset=30)
    api.commit()

    reminder1.delete()
    response = api.commit()
    assert response['reminders'][0]['is_deleted'] == 1
    assert reminder1['id'] not in [p['id'] for p in api.state['reminders']]

    item1.delete()
    api.commit()


def test_reminder_relative_update(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1', due={'string': 'tomorrow 5pm'})
    api.commit()
    reminder1 = api.reminders.add(item1['id'], minute_offset=30)
    api.commit()

    reminder1.update(minute_offset=str(15))
    response = api.commit()
    assert response['reminders'][0]['minute_offset'] == 15
    assert reminder1['id'] in [p['id'] for p in api.state['reminders']]
    assert api.reminders.get_by_id(reminder1['id']) == reminder1

    reminder1.delete()
    api.commit()
    item1.delete()
    api.commit()


def test_reminder_absolute_add(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1', due={'string': 'tomorrow 5pm'})
    api.commit()

    now = time.time()
    tomorrow = time.gmtime(now + 24 * 3600)
    due_date_utc = time.strftime("%Y-%m-%dT%H:%M:%SZ", tomorrow)
    reminder1 = api.reminders.add(item1['id'], due={'date': due_date_utc})
    response = api.commit()
    assert response['reminders'][0]['due']['date'] == due_date_utc
    tomorrow = time.gmtime(time.time() + 24 * 3600)
    assert reminder1['id'] in [p['id'] for p in api.state['reminders']]
    assert api.reminders.get_by_id(reminder1['id']) == reminder1

    reminder1.delete()
    api.commit()
    item1.delete()
    api.commit()


def test_reminder_absolute_delete(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1', due={'string': 'tomorrow 5pm'})
    api.commit()

    now = time.time()
    tomorrow = time.gmtime(now + 24 * 3600)
    due_date_utc = time.strftime("%Y-%m-%dT%H:%M:%SZ", tomorrow)
    reminder1 = api.reminders.add(item1['id'], due={'date': due_date_utc})
    api.commit()

    api.reminders.delete(reminder1['id'])
    response = api.commit()
    assert response['reminders'][0]['is_deleted'] == 1
    assert reminder1['id'] not in [p['id'] for p in api.state['reminders']]

    item1.delete()
    response = api.commit()


def test_reminder_absolute_update(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api.sync()

    item1 = api.items.add('Item1', due={'string': 'tomorrow 5pm'})
    api.commit()

    now = time.time()
    tomorrow = time.gmtime(now + 24 * 3600)
    due_date_utc = time.strftime("%Y-%m-%dT%H:%M:%SZ", tomorrow)
    reminder1 = api.reminders.add(item1['id'], due={'date': due_date_utc})
    api.commit()

    tomorrow = time.gmtime(now + 24 * 3600 + 60)
    due_date_utc = time.strftime("%Y-%m-%dT%H:%M:%SZ", tomorrow)
    api.reminders.update(reminder1['id'], due_date_utc=due_date_utc)
    response = api.commit()
    assert response['reminders'][0]['due']['date'] == due_date_utc
    assert reminder1['id'] in [p['id'] for p in api.state['reminders']]
    assert api.reminders.get_by_id(reminder1['id']) == reminder1

    reminder1.delete()
    api.commit()
    item1.delete()
    api.commit()


def test_locations(api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)

    api.sync()

    api.locations.clear()
    api.commit()

    assert api.state['locations'] == []


def test_live_notifications(api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)

    api.sync()

    api.live_notifications.set_last_read(
        api.state['live_notifications_last_read_id'])
    response = api.commit()
    assert response['live_notifications_last_read_id'] == \
        api.state['live_notifications_last_read_id']


def test_share_accept(cleanup, cleanup2, api_endpoint, api_token, api_token2):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api2 = todoist.api.TodoistAPI(api_token2, api_endpoint)

    api.user.update(auto_invite_disabled=1)
    api.commit()
    api.sync()

    api2.user.update(auto_invite_disabled=1)
    api2.commit()
    api2.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    api.projects.share(project1['id'], api2.state['user']['email'])
    response = api.commit()
    assert response['projects'][0]['name'] == project1['name']
    assert response['projects'][0]['shared']

    response2 = api2.sync()
    invitation1 = next((ln for ln in response2['live_notifications']
                        if ln['notification_type'] == 'share_invitation_sent'),
                       None)
    assert invitation1 is not None
    assert invitation1['project_name'] == project1['name']
    assert invitation1['from_user']['email'] == api.state['user']['email']

    api2.invitations.accept(invitation1['id'],
                            invitation1['invitation_secret'])
    response2 = api2.commit()
    assert api2.state['user']['id'] in \
        [p['user_id'] for p in api2.state['collaborator_states']]

    api.sync()
    project1 = [p for p in api.state['projects'] if p['name'] == 'Project1'][0]
    project1.delete()
    api.commit()


def test_share_reject(cleanup, cleanup2, api_endpoint, api_token, api_token2):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api2 = todoist.api.TodoistAPI(api_token2, api_endpoint)

    api.user.update(auto_invite_disabled=1)
    api.commit()
    api.sync()

    api2.user.update(auto_invite_disabled=1)
    api2.commit()
    api2.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    api.projects.share(project1['id'], api2.state['user']['email'])
    response = api.commit()
    assert response['projects'][0]['name'] == project1['name']
    assert response['projects'][0]['shared']

    response2 = api2.sync()
    invitation2 = next((ln for ln in response2['live_notifications']
                        if ln['notification_type'] == 'share_invitation_sent'),
                       None)
    assert invitation2 is not None
    assert invitation2['project_name'] == project1['name']
    assert invitation2['from_user']['email'] == api.state['user']['email']

    api2.invitations.reject(invitation2['id'],
                            invitation2['invitation_secret'])
    response2 = api2.commit()
    assert len(response2['projects']) == 0
    assert len(response2['collaborator_states']) == 0

    project1 = [p for p in api.state['projects'] if p['name'] == 'Project1'][0]
    project1.delete()
    api.commit()


def test_share_delete(cleanup, cleanup2, api_endpoint, api_token, api_token2):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)
    api2 = todoist.api.TodoistAPI(api_token2, api_endpoint)

    api.user.update(auto_invite_disabled=1)
    api.commit()
    api.sync()

    api2.user.update(auto_invite_disabled=1)
    api2.commit()
    api2.sync()

    project1 = api.projects.add('Project1')
    api.commit()

    api.projects.share(project1['id'], api2.state['user']['email'])
    response = api.commit()
    assert response['projects'][0]['name'] == project1['name']
    assert response['projects'][0]['shared']

    response2 = api2.sync()
    invitation3 = next((ln for ln in response2['live_notifications']
                        if ln['notification_type'] == 'share_invitation_sent'),
                       None)
    assert invitation3 is not None
    assert invitation3['project_name'] == project1['name']
    assert invitation3['from_user']['email'] == api.state['user']['email']

    api.invitations.delete(invitation3['id'])
    api.commit()

    project1 = [p for p in api.state['projects'] if p['name'] == 'Project1'][0]
    project1.delete()
    api.commit()


def test_templates(cleanup, api_endpoint, api_token):
    api = todoist.api.TodoistAPI(api_token, api_endpoint)

    api.sync()

    project1 = api.projects.add('Project1')
    project2 = api.projects.add('Project2')
    api.commit()

    item1 = api.items.add('Item1', project_id=project1['id'])
    api.commit()

    template = api.templates.export_as_file(project1['id'])
    assert 'task,Item1,4,1' in template
    with io.open('/tmp/example.csv', 'w', encoding='utf-8') as example:
        example.write(template)

    result = api.templates.import_into_project(project1['id'],
                                               '/tmp/example.csv')
    assert result == {'status': u'ok'}

    item1.delete()
    api.commit()
    project1.delete()
    api.commit()
    project2.delete()
    api.commit()

[((8, 10, 8, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(8, 33, 8, 42): 'api_token', (8, 44, 8, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((17, 10, 17, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(17, 33, 17, 42): 'api_token', (17, 44, 17, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((31, 10, 31, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(31, 33, 31, 42): 'api_token', (31, 44, 31, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((44, 10, 44, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(44, 33, 44, 42): 'api_token', (44, 44, 44, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((58, 10, 58, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(58, 33, 58, 42): 'api_token', (58, 44, 58, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((72, 10, 72, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(72, 33, 72, 42): 'api_token', (72, 44, 72, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((89, 10, 89, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(89, 33, 89, 42): 'api_token', (89, 44, 89, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((110, 10, 110, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(110, 33, 110, 42): 'api_token', (110, 44, 110, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((133, 10, 133, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(133, 33, 133, 42): 'api_token', (133, 44, 133, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((157, 10, 157, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(157, 33, 157, 42): 'api_token', (157, 44, 157, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((192, 10, 192, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(192, 33, 192, 42): 'api_token', (192, 44, 192, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((207, 10, 207, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(207, 33, 207, 42): 'api_token', (207, 44, 207, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((221, 10, 221, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(221, 33, 221, 42): 'api_token', (221, 44, 221, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((238, 10, 238, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(238, 33, 238, 42): 'api_token', (238, 44, 238, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((261, 10, 261, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(261, 33, 261, 42): 'api_token', (261, 44, 261, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((286, 10, 286, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(286, 33, 286, 42): 'api_token', (286, 44, 286, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((311, 10, 311, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(311, 33, 311, 42): 'api_token', (311, 44, 311, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((338, 10, 338, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(338, 33, 338, 42): 'api_token', (338, 44, 338, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((361, 10, 361, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(361, 33, 361, 42): 'api_token', (361, 44, 361, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((384, 10, 384, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(384, 33, 384, 42): 'api_token', (384, 44, 384, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((390, 10, 390, 21), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((391, 15, 391, 43), 'time.gmtime', 'time.gmtime', ({(391, 27, 391, 42): 'now + 24 * 3600'}, {}), '(now + 24 * 3600)', False, 'import time\n'), ((392, 19, 392, 64), 'time.strftime', 'time.strftime', ({(392, 33, 392, 53): '"""%Y-%m-%dT%H:%M:%SZ"""', (392, 55, 392, 63): 'tomorrow'}, {}), "('%Y-%m-%dT%H:%M:%SZ', tomorrow)", False, 'import time\n'), ((409, 10, 409, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(409, 33, 409, 42): 'api_token', (409, 44, 409, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((443, 10, 443, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(443, 33, 443, 42): 'api_token', (443, 44, 443, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((469, 10, 469, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(469, 33, 469, 42): 'api_token', (469, 44, 469, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((483, 10, 483, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(483, 33, 483, 42): 'api_token', (483, 44, 483, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((497, 10, 497, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(497, 33, 497, 42): 'api_token', (497, 44, 497, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((514, 10, 514, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(514, 33, 514, 42): 'api_token', (514, 44, 514, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((543, 10, 543, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(543, 33, 543, 42): 'api_token', (543, 44, 543, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((562, 10, 562, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(562, 33, 562, 42): 'api_token', (562, 44, 562, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((583, 10, 583, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(583, 33, 583, 42): 'api_token', (583, 44, 583, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((604, 10, 604, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(604, 33, 604, 42): 'api_token', (604, 44, 604, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((623, 10, 623, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(623, 33, 623, 42): 'api_token', (623, 44, 623, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((644, 10, 644, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(644, 33, 644, 42): 'api_token', (644, 44, 644, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((665, 10, 665, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(665, 33, 665, 42): 'api_token', (665, 44, 665, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((679, 10, 679, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(679, 33, 679, 42): 'api_token', (679, 44, 679, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((693, 10, 693, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(693, 33, 693, 42): 'api_token', (693, 44, 693, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((710, 10, 710, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(710, 33, 710, 42): 'api_token', (710, 44, 710, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((742, 10, 742, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(742, 33, 742, 42): 'api_token', (742, 44, 742, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((761, 10, 761, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(761, 33, 761, 42): 'api_token', (761, 44, 761, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((779, 10, 779, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(779, 33, 779, 42): 'api_token', (779, 44, 779, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((800, 10, 800, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(800, 33, 800, 42): 'api_token', (800, 44, 800, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((806, 10, 806, 21), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((807, 15, 807, 43), 'time.gmtime', 'time.gmtime', ({(807, 27, 807, 42): 'now + 24 * 3600'}, {}), '(now + 24 * 3600)', False, 'import time\n'), ((808, 19, 808, 64), 'time.strftime', 'time.strftime', ({(808, 33, 808, 53): '"""%Y-%m-%dT%H:%M:%SZ"""', (808, 55, 808, 63): 'tomorrow'}, {}), "('%Y-%m-%dT%H:%M:%SZ', tomorrow)", False, 'import time\n'), ((823, 10, 823, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(823, 33, 823, 42): 'api_token', (823, 44, 823, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((829, 10, 829, 21), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((830, 15, 830, 43), 'time.gmtime', 'time.gmtime', ({(830, 27, 830, 42): 'now + 24 * 3600'}, {}), '(now + 24 * 3600)', False, 'import time\n'), ((831, 19, 831, 64), 'time.strftime', 'time.strftime', ({(831, 33, 831, 53): '"""%Y-%m-%dT%H:%M:%SZ"""', (831, 55, 831, 63): 'tomorrow'}, {}), "('%Y-%m-%dT%H:%M:%SZ', tomorrow)", False, 'import time\n'), ((845, 10, 845, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(845, 33, 845, 42): 'api_token', (845, 44, 845, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((851, 10, 851, 21), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((852, 15, 852, 43), 'time.gmtime', 'time.gmtime', ({(852, 27, 852, 42): 'now + 24 * 3600'}, {}), '(now + 24 * 3600)', False, 'import time\n'), ((853, 19, 853, 64), 'time.strftime', 'time.strftime', ({(853, 33, 853, 53): '"""%Y-%m-%dT%H:%M:%SZ"""', (853, 55, 853, 63): 'tomorrow'}, {}), "('%Y-%m-%dT%H:%M:%SZ', tomorrow)", False, 'import time\n'), ((857, 15, 857, 48), 'time.gmtime', 'time.gmtime', ({(857, 27, 857, 47): 'now + 24 * 3600 + 60'}, {}), '(now + 24 * 3600 + 60)', False, 'import time\n'), ((858, 19, 858, 64), 'time.strftime', 'time.strftime', ({(858, 33, 858, 53): '"""%Y-%m-%dT%H:%M:%SZ"""', (858, 55, 858, 63): 'tomorrow'}, {}), "('%Y-%m-%dT%H:%M:%SZ', tomorrow)", False, 'import time\n'), ((872, 10, 872, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(872, 33, 872, 42): 'api_token', (872, 44, 872, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((883, 10, 883, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(883, 33, 883, 42): 'api_token', (883, 44, 883, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((895, 10, 895, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(895, 33, 895, 42): 'api_token', (895, 44, 895, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((896, 11, 896, 59), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(896, 34, 896, 44): 'api_token2', (896, 46, 896, 58): 'api_endpoint'}, {}), '(api_token2, api_endpoint)', False, 'import todoist\n'), ((935, 10, 935, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(935, 33, 935, 42): 'api_token', (935, 44, 935, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((936, 11, 936, 59), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(936, 34, 936, 44): 'api_token2', (936, 46, 936, 58): 'api_endpoint'}, {}), '(api_token2, api_endpoint)', False, 'import todoist\n'), ((974, 10, 974, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(974, 33, 974, 42): 'api_token', (974, 44, 974, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((975, 11, 975, 59), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(975, 34, 975, 44): 'api_token2', (975, 46, 975, 58): 'api_endpoint'}, {}), '(api_token2, api_endpoint)', False, 'import todoist\n'), ((1010, 10, 1010, 57), 'todoist.api.TodoistAPI', 'todoist.api.TodoistAPI', ({(1010, 33, 1010, 42): 'api_token', (1010, 44, 1010, 56): 'api_endpoint'}, {}), '(api_token, api_endpoint)', False, 'import todoist\n'), ((1023, 9, 1023, 59), 'io.open', 'io.open', (), '', False, 'import io\n'), ((812, 27, 812, 38), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n')]