import unittest
from tempfile import mkstemp
from os import remove
from datetime import date, datetime, timedelta
from sys import version

from qtodotxt2.lib.file import File
from qtodotxt2.lib.tasklib import Task
from qtodotxt2.lib.filters import DueTodayFilter, DueTomorrowFilter, DueThisWeekFilter, DueThisMonthFilter, DueOverdueFilter


PYTHON_VERSION = version[:3]


if PYTHON_VERSION < '3.3':
    FileNotFoundError = BaseException


class TestFile(unittest.TestCase):
    def setUp(self):
        self.file = File()
        self.tmpfile = mkstemp(text=True)[1]

    def tearDown(self):
        try:
            remove(self.tmpfile)
        except FileNotFoundError:
            pass
        except OSError as ex:    # maintain compatibility with Python 3.2
            if ex.errno != 2:
                raise
        except:
            raise

    def saveAndReload(self):
        self.file.save(self.tmpfile)
        self.file = File()
        self.file.load(self.tmpfile)

    def test_single_task(self):
        text = 'due:1999-10-10 do something +project1 @context1'
        self.file.tasks.append(Task(text))
        self.saveAndReload()
        self.assertEqual(self.file.tasks[0].text, text)
        self.assertEqual(self.file.tasks[0].contexts, ['context1'])
        self.assertEqual(self.file.tasks[0].projects, ['project1'])
        self.assertFalse(self.file.tasks[0].is_complete)
        self.assertFalse(self.file.tasks[0].priority)
        self.assertEqual(self.file.tasks[0].due, datetime(1999, 10, 10))

    def test_two_tasks(self):
        task1 = 'do something +project1 @context1'
        task2 = '(A) do something else +project1 @context2'
        self.file.tasks.extend([
            Task(task1),
            Task(task2)
        ])
        self.saveAndReload()
        self.assertEqual(self.file.tasks[0].text, task1)
        self.assertEqual(self.file.tasks[1].text, task2)

    def test_five_tasks(self):
        task1 = Task('do something +project1 @context1')
        task2 = Task('(A) do something else +project1 @context2')
        task3 = Task('do something else +project1 @context2')
        task4 = Task('something else +project1 @context2')
        task5 = Task('abc +project1 @context2')
        self.file.tasks.extend([task1, task2, task3, task4, task5])
        self.saveAndReload()
        self.assertEqual(self.file.tasks[0].text, task1.text)
        self.assertEqual(self.file.tasks[1].text, task2.text)
        self.assertEqual(self.file.tasks[2].text, task3.text)
        self.assertEqual(self.file.tasks[3].text, task4.text)
        self.assertEqual(self.file.tasks[4].text, task5.text)

    def test_get_all_contexts(self):
        self.file.tasks.extend([
            Task('x task with @context1'),
            Task('task with @context2'),
            Task('task with @context1 and @context2'),
            Task('task with @context1 and @context2 and @context3')
        ])
        self.saveAndReload()
        self.assertEqual(self.file.getAllContexts(), {'context1': [2, 1], 'context2': [3, 0], 'context3': [1, 0]})

    def test_get_all_incl_completed_contexts(self):
        self.file.tasks.extend([
            Task('x task with @context1'),
            Task('task with @context2'),
            Task('task with @context1 and @context2'),
            Task('x task with @context1 and @context2 and @context3')
        ])
        self.saveAndReload()
        self.assertEqual(self.file.getAllContexts(), {'context1': [1, 2], 'context2': [2, 1], 'context3': [0, 1]})

    def test_get_all_projects(self):
        self.file.tasks.extend([
            Task('x task with +project1'),
            Task('task with +project2'),
            Task('task with +project1 and +project2'),
            Task('task with +project1 and +project2 and +project3')
        ])
        self.saveAndReload()
        self.assertEqual(self.file.getAllProjects(), {'project1': [2, 1], 'project2': [3, 0], 'project3': [1, 0]})

    def test_get_all_due_ranges(self):
        today = date.today().strftime('%Y-%m-%d')
        yesterday = (date.today() - timedelta(days=1)).strftime('%Y-%m-%d')

        self.file.tasks.extend([
            Task('x due:' + today + ' completed task of today'),
            Task('due:' + today + ' first task of today'),
            Task('due:' + today + ' second task of today'),
            Task('due:' + yesterday + ' task of yesterday'),
        ])
        self.saveAndReload()
        due = self.file.getAllDueRanges()
        print(due)
        self.assertEqual(due[DueTodayFilter()], [2, 1])
        self.assertEqual(due[DueOverdueFilter()], [1, 0])
        self.assertEqual(due[DueThisWeekFilter()], [2, 1])

    def test_load_empty_filename(self):
        self.assertRaises(OSError, self.file.load, '')

    def test_load_nonexisting_file(self):
        remove(self.tmpfile)
        self.assertRaises(OSError, self.file.load, self.tmpfile)
