import datetime
from django.utils import timezone
from django.test import TestCase
from django.contrib.auth.models import (
    User,
)
from wasch.models import (
    Appointment,
    WashUser,
    WashParameters,
    # not models:
    AppointmentError,
    StatusRights,
)
from wasch import tvkutils, payment


class WashUserTestCase(TestCase):
    def test_god(self):
        god, _ = WashUser.objects.get_or_create_god()
        self.assertTrue(god.isActivated)
        self.assertTrue(god.user.is_staff)
        self.assertTrue(god.user.is_superuser)
        group_names = (group.name for group in god.user.groups.all())
        for expected_group in StatusRights(9).groups:
            self.assertIn(expected_group, group_names)


class AppointmentTestCase(TestCase):
    exampleUserName = 'waschexample'
    examplePoorUserName = 'poor'
    exampleTime = Appointment.manager.scheduled_appointment_times()[-1]
    exampleTooOldTime = timezone.make_aware(datetime.datetime(1991, 12, 25))
    exampleTooOldReference = 4481037
    exampleMachine, exampleBrokenMachine, lastMachine = \
        tvkutils.get_or_create_machines()[0]

    def setUp(self):
        tvkutils.setup()
        self.exampleMachine.isAvailable = True  # though this is default
        self.exampleMachine.save()
        self.exampleBrokenMachine.isAvailable = False
        self.exampleMachine.save()
        WashUser.objects.create_enduser(self.exampleUserName, isActivated=True)
        WashUser.objects.create_enduser(
            self.examplePoorUserName, isActivated=False)

    def _createExample(self):
        user = User.objects.get(username=self.exampleUserName)
        return Appointment.objects.create(
            time=self.exampleTime, machine=self.exampleMachine, user=user,
            wasUsed=False)

    def test_create(self):
        result = self._createExample()
        self.assertEqual(result.time, self.exampleTime)
        self.assertEqual(result.machine, self.exampleMachine)
        self.assertEqual(result.user.username, self.exampleUserName)
        self.assertTrue(Appointment.manager.appointment_exists(
            result.time, result.machine))
        self.assertFalse(Appointment.manager.bookable(
            result.time, result.machine, result.user))
        self.assertEqual(
            Appointment.manager.why_not_bookable(
                result.time, result.machine, result.user),
            41,  # Appointment taken
        )
        result.cancel()
        self.assertTrue(Appointment.manager.bookable(
            result.time, result.machine, result.user))

    def test_bookable(self):
        user = User.objects.get(username=self.exampleUserName)
        poorUser = User.objects.get(username=self.examplePoorUserName)
        god, _ = WashUser.objects.get_or_create_god()
        self.assertEqual(
            Appointment.manager.why_not_bookable(
                self.exampleTime, self.exampleMachine, poorUser),
            31,  # User not active
        )
        self.assertTrue(Appointment.manager.bookable(
            self.exampleTime, self.exampleMachine, user))
        self.assertTrue(Appointment.manager.bookable(
            self.exampleTime, self.exampleMachine, god.user))
        self.assertEqual(
            Appointment.manager.why_not_bookable(
                self.exampleTooOldTime, self.exampleMachine, user),
            11,  # Unsupported time
        )
        unsavedTooOldAppointment = Appointment.from_reference(
            self.exampleTooOldReference, user)
        self.assertEqual(self.exampleTooOldReference, Appointment(
            time=self.exampleTooOldTime, machine=self.exampleMachine,
            user=user).reference)
        self.assertEqual(unsavedTooOldAppointment.time, self.exampleTooOldTime)
        self.assertEqual(unsavedTooOldAppointment.machine, self.exampleMachine)
        self.assertEqual(
            unsavedTooOldAppointment.user.username, self.exampleUserName)
        self.assertEqual(
            unsavedTooOldAppointment.reference, self.exampleTooOldReference)
        self.assertEqual(
            Appointment.manager.why_not_bookable(
                self.exampleTime, self.exampleBrokenMachine, user),
            21,  # Machine out of service
        )

    def test_make_appointment(self):
        user = User.objects.get(username=self.exampleUserName)
        god, _ = WashUser.objects.get_or_create_god()
        appointment = Appointment.manager.make_appointment(
            self.exampleTime, self.exampleMachine, user)
        reference = appointment.reference
        self.assertEqual(
            Appointment.manager.why_not_bookable(
                self.exampleTime, self.exampleMachine, god.user),
            41,  # Appointment taken
        )
        with self.assertRaises(AppointmentError) as ae:
            Appointment.manager.make_appointment(
                self.exampleTime, self.exampleMachine, user)
        self.assertEqual(ae.exception.reason, 41)
        appointment.cancel()
        self.assertEqual(
            appointment,
            Appointment.manager.filter_for_reference(reference).get())
        WashParameters.objects.update_value('bonus-method', 'empty')
        self.assertTrue(Appointment.manager.bookable(
            self.exampleTime, self.exampleMachine, user))
        with self.assertRaises(payment.PaymentError):
            Appointment.manager.make_appointment(
                self.exampleTime, self.exampleMachine, user)

    def test_use(self):
        user = User.objects.get(username=self.exampleUserName)
        appointment = Appointment.manager.make_appointment(
            self.exampleTime, self.exampleMachine, user)
        appointment.use()
        with self.assertRaises(AppointmentError) as ae:
            appointment.use()
        self.assertEqual(ae.exception.reason, 61)  # Appointment already used
        with self.assertRaises(AppointmentError) as ae:
            appointment.rebook()
        self.assertEqual(ae.exception.reason, 41)  # Appointment taken
        with self.assertRaises(AppointmentError) as ae:
            appointment.cancel()
        self.assertEqual(ae.exception.reason, 61)  # Appointment already used
        self.assertTrue(appointment.wasUsed)

[((20, 17, 20, 53), 'wasch.models.WashUser.objects.get_or_create_god', 'WashUser.objects.get_or_create_god', ({}, {}), '()', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((32, 18, 32, 67), 'wasch.models.Appointment.manager.scheduled_appointment_times', 'Appointment.manager.scheduled_appointment_times', ({}, {}), '()', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((33, 44, 33, 75), 'datetime.datetime', 'datetime.datetime', ({(33, 62, 33, 66): '1991', (33, 68, 33, 70): '12', (33, 72, 33, 74): '25'}, {}), '(1991, 12, 25)', False, 'import datetime\n'), ((36, 8, 36, 41), 'wasch.tvkutils.get_or_create_machines', 'tvkutils.get_or_create_machines', ({}, {}), '()', False, 'from wasch import tvkutils, payment\n'), ((39, 8, 39, 24), 'wasch.tvkutils.setup', 'tvkutils.setup', ({}, {}), '()', False, 'from wasch import tvkutils, payment\n'), ((44, 8, 44, 79), 'wasch.models.WashUser.objects.create_enduser', 'WashUser.objects.create_enduser', (), '', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((45, 8, 46, 56), 'wasch.models.WashUser.objects.create_enduser', 'WashUser.objects.create_enduser', (), '', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((49, 15, 49, 62), 'django.contrib.auth.models.User.objects.get', 'User.objects.get', (), '', False, 'from django.contrib.auth.models import User\n'), ((50, 15, 52, 26), 'wasch.models.Appointment.objects.create', 'Appointment.objects.create', (), '', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((73, 15, 73, 62), 'django.contrib.auth.models.User.objects.get', 'User.objects.get', (), '', False, 'from django.contrib.auth.models import User\n'), ((74, 19, 74, 70), 'django.contrib.auth.models.User.objects.get', 'User.objects.get', (), '', False, 'from django.contrib.auth.models import User\n'), ((75, 17, 75, 53), 'wasch.models.WashUser.objects.get_or_create_god', 'WashUser.objects.get_or_create_god', ({}, {}), '()', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((90, 35, 91, 46), 'wasch.models.Appointment.from_reference', 'Appointment.from_reference', ({(91, 12, 91, 39): 'self.exampleTooOldReference', (91, 41, 91, 45): 'user'}, {}), '(self.exampleTooOldReference, user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((108, 15, 108, 62), 'django.contrib.auth.models.User.objects.get', 'User.objects.get', (), '', False, 'from django.contrib.auth.models import User\n'), ((109, 17, 109, 53), 'wasch.models.WashUser.objects.get_or_create_god', 'WashUser.objects.get_or_create_god', ({}, {}), '()', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((110, 22, 111, 56), 'wasch.models.Appointment.manager.make_appointment', 'Appointment.manager.make_appointment', ({(111, 12, 111, 28): 'self.exampleTime', (111, 30, 111, 49): 'self.exampleMachine', (111, 51, 111, 55): 'user'}, {}), '(self.exampleTime, self.exampleMachine,\n    user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((126, 8, 126, 68), 'wasch.models.WashParameters.objects.update_value', 'WashParameters.objects.update_value', ({(126, 44, 126, 58): '"""bonus-method"""', (126, 60, 126, 67): '"""empty"""'}, {}), "('bonus-method', 'empty')", False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((134, 15, 134, 62), 'django.contrib.auth.models.User.objects.get', 'User.objects.get', (), '', False, 'from django.contrib.auth.models import User\n'), ((135, 22, 136, 56), 'wasch.models.Appointment.manager.make_appointment', 'Appointment.manager.make_appointment', ({(136, 12, 136, 28): 'self.exampleTime', (136, 30, 136, 49): 'self.exampleMachine', (136, 51, 136, 55): 'user'}, {}), '(self.exampleTime, self.exampleMachine,\n    user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((25, 30, 25, 45), 'wasch.models.StatusRights', 'StatusRights', ({(25, 43, 25, 44): '(9)'}, {}), '(9)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((59, 24, 60, 40), 'wasch.models.Appointment.manager.appointment_exists', 'Appointment.manager.appointment_exists', ({(60, 12, 60, 23): 'result.time', (60, 25, 60, 39): 'result.machine'}, {}), '(result.time, result.machine)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((61, 25, 62, 53), 'wasch.models.Appointment.manager.bookable', 'Appointment.manager.bookable', ({(62, 12, 62, 23): 'result.time', (62, 25, 62, 39): 'result.machine', (62, 41, 62, 52): 'result.user'}, {}), '(result.time, result.machine, result.user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((64, 12, 65, 57), 'wasch.models.Appointment.manager.why_not_bookable', 'Appointment.manager.why_not_bookable', ({(65, 16, 65, 27): 'result.time', (65, 29, 65, 43): 'result.machine', (65, 45, 65, 56): 'result.user'}, {}), '(result.time, result.machine, result.user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((69, 24, 70, 53), 'wasch.models.Appointment.manager.bookable', 'Appointment.manager.bookable', ({(70, 12, 70, 23): 'result.time', (70, 25, 70, 39): 'result.machine', (70, 41, 70, 52): 'result.user'}, {}), '(result.time, result.machine, result.user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((77, 12, 78, 64), 'wasch.models.Appointment.manager.why_not_bookable', 'Appointment.manager.why_not_bookable', ({(78, 16, 78, 32): 'self.exampleTime', (78, 34, 78, 53): 'self.exampleMachine', (78, 55, 78, 63): 'poorUser'}, {}), '(self.exampleTime, self.exampleMachine,\n    poorUser)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((81, 24, 82, 56), 'wasch.models.Appointment.manager.bookable', 'Appointment.manager.bookable', ({(82, 12, 82, 28): 'self.exampleTime', (82, 30, 82, 49): 'self.exampleMachine', (82, 51, 82, 55): 'user'}, {}), '(self.exampleTime, self.exampleMachine, user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((83, 24, 84, 60), 'wasch.models.Appointment.manager.bookable', 'Appointment.manager.bookable', ({(84, 12, 84, 28): 'self.exampleTime', (84, 30, 84, 49): 'self.exampleMachine', (84, 51, 84, 59): 'god.user'}, {}), '(self.exampleTime, self.exampleMachine, god.user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((86, 12, 87, 66), 'wasch.models.Appointment.manager.why_not_bookable', 'Appointment.manager.why_not_bookable', ({(87, 16, 87, 38): 'self.exampleTooOldTime', (87, 40, 87, 59): 'self.exampleMachine', (87, 61, 87, 65): 'user'}, {}), '(self.exampleTooOldTime, self.\n    exampleMachine, user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((102, 12, 103, 66), 'wasch.models.Appointment.manager.why_not_bookable', 'Appointment.manager.why_not_bookable', ({(103, 16, 103, 32): 'self.exampleTime', (103, 34, 103, 59): 'self.exampleBrokenMachine', (103, 61, 103, 65): 'user'}, {}), '(self.exampleTime, self.\n    exampleBrokenMachine, user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((114, 12, 115, 64), 'wasch.models.Appointment.manager.why_not_bookable', 'Appointment.manager.why_not_bookable', ({(115, 16, 115, 32): 'self.exampleTime', (115, 34, 115, 53): 'self.exampleMachine', (115, 55, 115, 63): 'god.user'}, {}), '(self.exampleTime, self.exampleMachine,\n    god.user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((119, 12, 120, 60), 'wasch.models.Appointment.manager.make_appointment', 'Appointment.manager.make_appointment', ({(120, 16, 120, 32): 'self.exampleTime', (120, 34, 120, 53): 'self.exampleMachine', (120, 55, 120, 59): 'user'}, {}), '(self.exampleTime, self.exampleMachine,\n    user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((127, 24, 128, 56), 'wasch.models.Appointment.manager.bookable', 'Appointment.manager.bookable', ({(128, 12, 128, 28): 'self.exampleTime', (128, 30, 128, 49): 'self.exampleMachine', (128, 51, 128, 55): 'user'}, {}), '(self.exampleTime, self.exampleMachine, user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((130, 12, 131, 60), 'wasch.models.Appointment.manager.make_appointment', 'Appointment.manager.make_appointment', ({(131, 16, 131, 32): 'self.exampleTime', (131, 34, 131, 53): 'self.exampleMachine', (131, 55, 131, 59): 'user'}, {}), '(self.exampleTime, self.exampleMachine,\n    user)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((92, 54, 94, 22), 'wasch.models.Appointment', 'Appointment', (), '', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n'), ((125, 12, 125, 63), 'wasch.models.Appointment.manager.filter_for_reference', 'Appointment.manager.filter_for_reference', ({(125, 53, 125, 62): 'reference'}, {}), '(reference)', False, 'from wasch.models import Appointment, WashUser, WashParameters, AppointmentError, StatusRights\n')]