"""
This module provides tests for :py:mod:`userdbs.forms`.

"""
from django import forms
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse

from userdbs.forms import AddUserDatabaseForm, ChangeDatabaseUserPasswordForm
from userdbs.models import DB_TYPES

from unittest.mock import MagicMock, Mock, patch


Customer = get_user_model()


class AddUserDatabaseFormTest(TestCase):
    """
    Test class for :py:class:`userdbs.forms.AddUserDatabaseForm`.

    """

    def _setup_hostingpackage(self):
        self.hostingpackage = Mock(id=42)

    def test_constructor_needs_hostingpackage(self):
        with self.assertRaises(KeyError) as ke:
            AddUserDatabaseForm(instance=Mock())
        self.assertEqual(ke.exception.args[0], "hostingpackage")

    def test_constructor_needs_dbtypes(self):
        with self.assertRaises(KeyError) as ke:
            AddUserDatabaseForm(instance=Mock(), hostingpackage=Mock())
        self.assertEqual(ke.exception.args[0], "dbtypes")

    def test_constructor_one_dbtype(self):
        self._setup_hostingpackage()
        dbtypes = [(DB_TYPES.pgsql, DB_TYPES[DB_TYPES.pgsql])]
        form = AddUserDatabaseForm(
            instance=MagicMock(), hostingpackage=self.hostingpackage, dbtypes=dbtypes
        )
        self.assertIn("db_type", form.fields)
        self.assertEqual(form.fields["db_type"].choices, dbtypes)
        self.assertTrue(isinstance(form.fields["db_type"].widget, forms.HiddenInput))
        self.assertTrue(hasattr(form, "helper"))
        self.assertEqual(
            form.helper.form_action,
            reverse("add_userdatabase", kwargs={"package": self.hostingpackage.id}),
        )
        self.assertEqual(form.helper.inputs[0].name, "submit")

    def test_constructor_multiple_dbtypes(self):
        self._setup_hostingpackage()
        dbtypes = [
            (DB_TYPES.pgsql, DB_TYPES[DB_TYPES.pgsql]),
            (DB_TYPES.mysql, DB_TYPES[DB_TYPES.mysql]),
        ]
        form = AddUserDatabaseForm(
            instance=MagicMock(), hostingpackage=self.hostingpackage, dbtypes=dbtypes
        )
        self.assertIn("db_type", form.fields)
        self.assertEqual(form.fields["db_type"].choices, dbtypes)
        self.assertTrue(isinstance(form.fields["db_type"].widget, forms.RadioSelect))
        self.assertTrue(hasattr(form, "helper"))
        self.assertEqual(
            form.helper.form_action,
            reverse("add_userdatabase", kwargs={"package": self.hostingpackage.id}),
        )
        self.assertEqual(form.helper.inputs[0].name, "submit")

    @patch("userdbs.forms.UserDatabase.objects.create_userdatabase_with_user")
    def test_save(self, create_userdatabase_with_user):
        self._setup_hostingpackage()
        dbtypes = [
            (DB_TYPES.pgsql, DB_TYPES[DB_TYPES.pgsql]),
            (DB_TYPES.mysql, DB_TYPES[DB_TYPES.mysql]),
        ]
        form = AddUserDatabaseForm(
            instance=MagicMock(), hostingpackage=self.hostingpackage, dbtypes=dbtypes
        )
        form.cleaned_data = {"db_type": DB_TYPES.pgsql, "password1": "secret"}
        form.save()
        self.assertTrue(
            create_userdatabase_with_user.called_with(
                DB_TYPES.pgsql,
                self.hostingpackage.osuser,
                password="secret",
                commit=True,
            )
        )


class ChangeDatabaseUserPasswordFormTest(TestCase):
    """
    Test class for :py:class:`userdbs.forms.ChangeDatabaseUserPasswordForm`.

    """

    def _setup_hostingpackage(self):
        self.hostingpackage = Mock(id=42)

    def test_constructor_needs_hostingpackage(self):
        with self.assertRaises(KeyError) as ke:
            ChangeDatabaseUserPasswordForm(instance=Mock())
        self.assertEqual(ke.exception.args[0], "hostingpackage")

    def test_constructor(self):
        self._setup_hostingpackage()
        instance = MagicMock()
        instance.name = "test"
        form = ChangeDatabaseUserPasswordForm(
            instance=instance, hostingpackage=self.hostingpackage
        )
        self.assertIn("password1", form.fields)
        self.assertIn("password2", form.fields)
        self.assertTrue(hasattr(form, "helper"))
        self.assertEqual(
            form.helper.form_action,
            reverse("change_dbuser_password", kwargs={"slug": "test", "package": 42}),
        )
        self.assertEqual(form.helper.inputs[0].name, "submit")

    def test_save(self):
        instance = MagicMock()
        instance.name = "test"
        self._setup_hostingpackage()
        form = ChangeDatabaseUserPasswordForm(
            instance=instance, hostingpackage=self.hostingpackage
        )
        form.cleaned_data = {"password1": "secret"}
        form.save()
        self.assertTrue(instance.set_password.called_with("secret"))
