import datetime
import pytest
import subprocess

from composer.timeperiod import (
    Day,
    Week,
    Month,
    Quarter,
    Year,
    is_weekend,
    quarter_for_month,
)

from ...fixtures import planner


class TestCreateLog(object):
    """Check that new templates generated by the planner are as expected"""

    def _year_template(self, planner, for_day):
        template = ""
        template += "= %s =\n" % for_day.year
        template += "\n"
        template += "\t* [[%s 2013]]\n" % quarter_for_month(for_day.month)
        template += "\n"
        template += "CHECKPOINTS:\n"
        template += planner.checkpoints_year_file.getvalue()
        template += "\n"
        template += "AGENDA:\n"
        template += "\n"
        template += "YEARLYs:\n"
        template += planner.periodic_year_file.getvalue()
        template += "\n"
        template += "NOTES:\n"
        template += "\n"
        template += "\n"
        template += "TIME SPENT ON PLANNER: "
        return template

    def test_year(self, planner):
        """Test that year template is generated correctly by integrating
        checkpoints, periodic, etc.
        """
        for_day = datetime.date(2013, 6, 5)

        planner.create_log(Year, for_day)
        expected = self._year_template(planner, for_day)
        assert planner.next_day_planner.yearfile.read() == expected

    def _quarter_template(self, planner, for_day):
        template = ""
        template += "= %s %s =\n" % (
            quarter_for_month(for_day.month),
            for_day.year,
        )
        template += "\n"
        template += "\t* [[Month of December, 2012]]\n"
        template += "\n"
        template += "CHECKPOINTS:\n"
        template += planner.checkpoints_quarter_file.getvalue()
        template += "\n"
        template += "AGENDA:\n"
        template += "\n"
        template += "QUARTERLYs:\n"
        template += planner.periodic_quarter_file.getvalue()
        template += "\n"
        template += "NOTES:\n"
        template += "\n"
        template += "\n"
        template += "TIME SPENT ON PLANNER: "
        return template

    def test_quarter(self, planner):
        """Test that quarter template is generated correctly by integrating
        checkpoints, periodic, etc.
        """
        for_day = datetime.date(2012, 12, 5)

        planner.create_log(Quarter, for_day)
        expected = self._quarter_template(planner, for_day)
        assert planner.next_day_planner.quarterfile.read() == expected

    def _month_template(self, planner, for_day):
        (month, year) = (for_day.strftime('%B'), for_day.year)
        template = "= %s %d =\n" % (month.upper(), year)
        template += "\n"

        # really, this template component should probably just be excluded
        # from tests in some way since it's externally generated. Or rather,
        # the tests shouldn't check for equality but something weaker
        calendar = subprocess.check_output(
            [
                'cal',
                '-h',
                '-d',
                '{year}-{month}'.format(year=year, month=for_day.month),
            ]
        ).decode('utf-8')
        calendar = calendar.splitlines()
        calendar = ["\t\t" + line for line in calendar]
        calendar = "\n".join(calendar)

        template += calendar
        template += "\n"

        template += "\t* [[Week of %s %d, %d]]\n" % (
            month,
            1,
            year,
        )  # week begins on the 1st
        template += "\n"
        template += "CHECKPOINTS:\n"
        template += planner.checkpoints_month_file.getvalue()
        template += "\n"
        template += "AGENDA:\n\n"
        template += "MONTHLYs:\n"
        template += planner.periodic_month_file.getvalue()
        template += "\n"
        template += "NOTES:\n\n\n"
        template += "TIME SPENT ON PLANNER: "
        return template

    def test_month(self, planner):
        """Test that month template is generated correctly by integrating
        checkpoints, periodic, etc.
        """
        for_day = datetime.date(2012, 12, 5)

        planner.create_log(Month, for_day)
        expected = self._month_template(planner, for_day)
        assert planner.next_day_planner.monthfile.read() == expected

    def _week_template(self, planner, for_day):
        (date, month, year) = (
            for_day.day,
            for_day.strftime('%B'),
            for_day.year,
        )
        template = (
            "= WEEK OF %s %d, %d =\n"
            % (month, 1, year)  # this week begins on the 1st
        ).upper()
        template += "\n"
        # the entry is for the actual day, not necessarily the 1st
        template += "\t* [[%s %d, %d]]\n" % (month, date, year)
        template += "\n"
        template += "CHECKPOINTS:\n"
        template += planner.checkpoints_week_file.getvalue()
        template += "\n"
        template += "AGENDA:\n\n"
        template += "WEEKLYs:\n"
        template += planner.periodic_week_file.getvalue()
        template += "\n"
        template += "NOTES:\n\n\n"
        template += "TIME SPENT ON PLANNER: "
        return template

    def test_week(self, planner):
        """Test that week template is generated correctly by integrating
        checkpoints, periodic, etc.
        """
        for_day = datetime.date(2012, 12, 1)

        planner.create_log(Week, for_day)

        expected = self._week_template(planner, for_day)
        assert planner.next_day_planner.weekfile.read() == expected

    def test_template_begins_at_start_of_period(self, planner):
        """Test that week template is generated correctly by integrating
        checkpoints, periodic, etc.
        """
        for_day = datetime.date(2012, 12, 5)

        planner.create_log(Week, for_day)

        expected = self._week_template(planner, for_day)
        assert planner.next_day_planner.weekfile.read() == expected

    def _tasklist_nextday(self):
        return (
            "TOMORROW:\n"
            "\n"
            "THIS WEEK:\n"
            "[\\] write a script to automatically pull from plan files into a current day in planner (replacing template files)\n"
            "[ ] help meags set up planner\n"
            "\t[x] create life mindmap with meags\n"
            "\t[x] incorporate life mindmap into planner with meags\n"
            "\t[x] swap meags' Esc and CapsLock on personal laptop\n"
            "\t[x] vim education and workflow\n"
            "\t[x] help meags build a routine of entering data for the day\n"
            "\t[ ] meags to schedule all activities (currently unscheduled)\n"
            "\t[ ] set up meags work laptop with vim/planner/truecrypt/dropbox\n"
            "\t[-] set up git access on your domain\n"
            "\t[ ] set up dropbox+truecrypt planner access for meags\n"
            "\n"
            "THIS MONTH:\n"
            "[ ] get India Tour reimbursement\n"
            "\t[x] resend all receipts and info to Amrit\n"
            "\t[x] send reminder email to Amrit\n"
            "\t[x] coordinate with amrit to go to stanford campus\n"
            "\t[x] remind amrit if no response\n"
            "\t[x] check Stanford calendar for appropriate time\n"
            "\t[x] email amrit re: thursday?\n"
            "\t[x] email amrit re: monday [$FRIDAY MORNING$]\n"
            "\t[x] wait for response\n"
            "\t[-] send reminder on Wed night\n"
            "\t[x] respond to amrit's email re: amount correction\n"
            "\t[x] wait to hear back [remind $MONDAY$]\n"
            "\t[-] followup with ASSU on reimbursement [$TUESDAY$]\n"
            "\t[x] pick up reimbursement, give difference check to raag\n"
            "\t[x] cash check\n"
            "\t[x] confirm deposit\n"
            "\t[ ] confirm debit of 810 by raag [$DECEMBER 10$]\n"
            "[ ] do residual monthlys\n"
            "[ ] get a good scratchy post for ferdy (fab?)\n"
            "\n"
            "SOMEDAY:\n"
        )

    def _day_template(self, planner, for_day):
        (date, day, month, year) = (
            for_day.day,
            for_day.strftime('%A'),
            for_day.strftime('%B'),
            for_day.year,
        )

        daythemes = (
            "SUNDAY: Groceries Day\n"
            "MONDAY: \n"
            "TUESDAY:Cleaning Day\n"
            "WEDNESDAY:\n"
            "THURSDAY:\n"
            "FRIDAY:\n"
            "SATURDAY: LAUNDRY DAY\n"
        )
        dailythemes = daythemes.lower()
        theme = dailythemes[dailythemes.index(day.lower()) :]
        theme = theme[theme.index(':') :].strip(': ')
        theme = theme[: theme.index('\n')].strip().upper()
        theme = "*" + theme + "*"

        template = ""
        template += "= %s %s %d, %d =\n" % (
            day.upper(),
            month[:3].upper(),
            date,
            year,
        )
        template += "\n"
        if len(theme) > 2:
            template += "Theme: %s\n" % theme
            template += "\n"
        template += "CHECKPOINTS:\n"
        if is_weekend(for_day):
            template += planner.checkpoints_weekend_file.getvalue()
        else:
            template += planner.checkpoints_weekday_file.getvalue()
        template += "\n"
        template += "AGENDA:\n"
        template += "[ ] contact dude\n"
        template += "[\\] make X\n"
        template += "[ ] call somebody\n"
        template += "[ ] finish project\n"
        template += "[ ] s'posed to do\n"
        template += "[\\] kinda did\n"
        template += "\n"
        template += "DAILYs:\n"
        template += planner.periodic_day_file.getvalue()
        template += "\n"
        template += "NOTES:\n\n\n"
        template += "TIME SPENT ON PLANNER: "
        return template

    @pytest.mark.parametrize("offset", range(7))
    def test_daily(self, planner, offset):
        """Test that templates for each day are generated correctly by
        integrating checkpoints, periodic, etc.
        Currently only 2 templates - weekday, and weekend are used.
        TODO: Add individual templates for each day of the week
        """

        for_day = datetime.date(2012, 12, 8) + datetime.timedelta(days=offset)
        expected_dayfile = self._day_template(planner, for_day)

        planner.create_log(Day, for_day)

        assert planner.next_day_planner.dayfile.read() == expected_dayfile
        expected_tasklist = self._tasklist_nextday()
        assert planner.tasklist.file.read() == expected_tasklist


class TestUpdateLog(object):
    """Check that updates on existing templates modifies the file as expected
    - does the right thing, does only that thing
    """

    def test_year(self, planner):
        """Check that writing over an existing year template adds the new
        quarter, and that there are no other changes
        """
        for_day = datetime.date(2012, 8, 9)

        yeartemplate_updated = (
            "= 2012 =\n"
            "\n"
            'Theme: *"PUT IT BACK" 2012*\n'
            "\n"
            "\t* [[Q3 2012]]\n"
            "\t* [[Q2 2012]]\n"
            "\t* [[Q1 2012]]\n"
            "\n"
            "CHECKPOINTS:\n"
            "[ ] Q1 - []\n"
            "[ ] Q2 - []\n"
            "[ ] Q3 - []\n"
            "[ ] Q4 - []\n"
            "\n"
            "AGENDA:\n"
            "\n"
            "YEARLYs:\n"
            "[ ] 1 significant life achievement\n"
            "\n"
            "NOTES:\n"
            "\n"
            "\n"
            "TIME SPENT ON PLANNER: \n"
        )

        planner.update_log(Year, for_day)
        assert planner.yearfile.read() == yeartemplate_updated

    def test_quarter(self, planner):
        """Check that writing over an existing quarter template adds the new
        month, and that there are no other changes
        """
        for_day = datetime.date(2012, 8, 9)

        quartertemplate_updated = (
            "= Q3 2012 =\n"
            "\n"
            "\t* [[Month of August, 2012]]\n"
            "\t* [[Month of July, 2012]]\n"
            "\n"
            "CHECKPOINTS:\n"
            "[ ] MONTH 1 - []\n"
            "[ ] MONTH 2 - []\n"
            "[ ] MONTH 3 - []\n"
            "\n"
            "AGENDA:\n"
            "\n"
            "QUARTERLYs:\n"
            "[ ] 1 major research achievement\n"
            "[ ] 1 major coding achievement\n"
            "[ ] 1 unique achievement\n"
            "[ ] update financials\n"
            "\n"
            "NOTES:\n"
            "\n"
            "\n"
            "TIME SPENT ON PLANNER: \n"
        )

        planner.update_log(Quarter, for_day)
        assert planner.quarterfile.read() == quartertemplate_updated

    def test_month(self, planner):
        """Check that writing over an existing month template adds the new
        week, and that there are no other changes
        """
        for_day = datetime.date(2012, 12, 9)

        monthtemplate_updated = (
            "= DECEMBER 2012 =\n"
            "\t* [[Week of December 9, 2012]]\n"
            "\t* [[Week of December 1, 2012]]\n"
            "\n"
            "CHECKPOINTS:\n"
            "[ ] WEEK 1 - []\n[ ] WEEK 2 - []\n[ ] WEEK 3 - []\n[ ] WEEK 4 - []\n"
            "\n"
            "AGENDA:\n"
            "\n"
            "MONTHLYs:\n"
            "[ ] Read 1 book\n[ ] Complete 1 nontrivial coding objective\n[ ] publish 1 blog post\n[ ] backup laptop data\n[ ] update financials\n"
            "\n"
            "NOTES:\n"
            "\n\n"
            "TIME SPENT ON PLANNER: "
        )

        planner.update_log(Month, for_day)
        assert planner.monthfile.read() == monthtemplate_updated

    def test_week(self, planner):
        """Check that writing over an existing week template adds the new day,
        and that there are no other changes
        """
        for_day = datetime.date(2012, 12, 5)

        weektemplate_updated = (
            "= WEEK OF DECEMBER 1, 2012 =\n"
            "\n"
            "Theme: *WEEK OF THEME*\n"
            "\n"
            "\t* [[December 5, 2012]]\n"
            "\t* [[December 4, 2012]]\n"
            "\t* [[December 3, 2012]]\n"
            "\t* [[December 2, 2012]]\n"
            "\t* [[December 1, 2012]]\n"
            "\n"
            "CHECKPOINTS:\n"
            "[ ] SUN - []\n[ ] MON - []\n[ ] TUE - []\n[ ] WED - []\n[ ] THU - []\n[ ] FRI - []\n[ ] SAT - []\n"
            "\n"
            "AGENDA:\n"
            "\n"
            "WEEKLYs:\n"
            "[ ] Complete 1 nontrivial research objective\n[ ] Meet+followup >= 1 person\n[ ] 6-10 hrs coding\n[ ] teach ferdy 1 trick\n"
            "\n"
            "NOTES:\n"
            "\n\n"
            "TIME SPENT ON PLANNER: "
        )

        planner.update_log(Week, for_day)
        assert planner.weekfile.read() == weektemplate_updated

    def test_jump_in_week(self, planner):
        """Check that writing over an existing week template in a jump adds
        the new day, and that there are no other changes
        """
        for_day = datetime.date(2012, 12, 8)

        weektemplate_updated = (
            "= WEEK OF DECEMBER 1, 2012 =\n"
            "\n"
            "Theme: *WEEK OF THEME*\n"
            "\n"
            "\t* [[December 8, 2012]]\n"
            "\t* [[December 4, 2012]]\n"
            "\t* [[December 3, 2012]]\n"
            "\t* [[December 2, 2012]]\n"
            "\t* [[December 1, 2012]]\n"
            "\n"
            "CHECKPOINTS:\n"
            "[ ] SUN - []\n[ ] MON - []\n[ ] TUE - []\n[ ] WED - []\n[ ] THU - []\n[ ] FRI - []\n[ ] SAT - []\n"
            "\n"
            "AGENDA:\n"
            "\n"
            "WEEKLYs:\n"
            "[ ] Complete 1 nontrivial research objective\n[ ] Meet+followup >= 1 person\n[ ] 6-10 hrs coding\n[ ] teach ferdy 1 trick\n"
            "\n"
            "NOTES:\n"
            "\n\n"
            "TIME SPENT ON PLANNER: "
        )

        planner.update_log(Week, for_day)
        assert planner.weekfile.read() == weektemplate_updated

    def test_jump_in_month(self, planner):
        """Check that writing over an existing month template in a jump adds
        the new week, and that there are no other changes
        """
        for_day = datetime.date(2012, 12, 19)

        monthtemplate_updated = (
            "= DECEMBER 2012 =\n"
            "\t* [[Week of December 16, 2012]]\n"
            "\t* [[Week of December 1, 2012]]\n"
            "\n"
            "CHECKPOINTS:\n"
            "[ ] WEEK 1 - []\n[ ] WEEK 2 - []\n[ ] WEEK 3 - []\n[ ] WEEK 4 - []\n"
            "\n"
            "AGENDA:\n"
            "\n"
            "MONTHLYs:\n"
            "[ ] Read 1 book\n[ ] Complete 1 nontrivial coding objective\n[ ] publish 1 blog post\n[ ] backup laptop data\n[ ] update financials\n"
            "\n"
            "NOTES:\n"
            "\n\n"
            "TIME SPENT ON PLANNER: "
        )

        planner.update_log(Month, for_day)
        assert planner.monthfile.read() == monthtemplate_updated

    def test_jump_in_quarter(self, planner):
        """Check that writing over an existing quarter template in a jump adds
        the new month, and that there are no other changes
        """
        for_day = datetime.date(2012, 9, 19)

        quartertemplate_updated = (
            "= Q3 2012 =\n"
            "\n"
            "\t* [[Month of September, 2012]]\n"
            "\t* [[Month of July, 2012]]\n"
            "\n"
            "CHECKPOINTS:\n"
            "[ ] MONTH 1 - []\n"
            "[ ] MONTH 2 - []\n"
            "[ ] MONTH 3 - []\n"
            "\n"
            "AGENDA:\n"
            "\n"
            "QUARTERLYs:\n"
            "[ ] 1 major research achievement\n"
            "[ ] 1 major coding achievement\n"
            "[ ] 1 unique achievement\n"
            "[ ] update financials\n"
            "\n"
            "NOTES:\n"
            "\n"
            "\n"
            "TIME SPENT ON PLANNER: \n"
        )

        planner.update_log(Quarter, for_day)
        assert planner.quarterfile.read() == quartertemplate_updated

    def test_jump_in_year(self, planner):
        """Check that writing over an existing year template in a jump adds
        the new quarter, and that there are no other changes
        """
        for_day = datetime.date(2012, 12, 19)

        yeartemplate_updated = (
            "= 2012 =\n"
            "\n"
            'Theme: *"PUT IT BACK" 2012*\n'
            "\n"
            "\t* [[Q4 2012]]\n"
            "\t* [[Q2 2012]]\n"
            "\t* [[Q1 2012]]\n"
            "\n"
            "CHECKPOINTS:\n"
            "[ ] Q1 - []\n"
            "[ ] Q2 - []\n"
            "[ ] Q3 - []\n"
            "[ ] Q4 - []\n"
            "\n"
            "AGENDA:\n"
            "\n"
            "YEARLYs:\n"
            "[ ] 1 significant life achievement\n"
            "\n"
            "NOTES:\n"
            "\n"
            "\n"
            "TIME SPENT ON PLANNER: \n"
        )

        planner.update_log(Year, for_day)
        assert planner.yearfile.read() == yeartemplate_updated
