from collections.abc import Iterable

import factory
from datetime import timedelta
from django.contrib.auth import get_user_model
from django.utils.timezone import now

from django_otp.plugins.otp_totp.models import TOTPDevice

from aidants_connect_web.models import (
    Autorisation,
    Connection,
    CarteTOTP,
    DatavizRegion,
    DatavizDepartment,
    DatavizDepartmentsToRegion,
    HabilitationRequest,
    Journal,
    Mandat,
    Organisation,
    OrganisationType,
    Usager,
)


class OrganisationFactory(factory.DjangoModelFactory):
    name = "COMMUNE D'HOULBEC COCHEREL"
    siret = 123
    address = "45 avenue du Général de Gaulle, 27120 HOULBEC COCHEREL"

    class Meta:
        model = Organisation


class CarteTOTPFactory(factory.DjangoModelFactory):
    serial_number = factory.Sequence(lambda n: f"SN{n}")
    seed = factory.Faker("hexify")

    class Meta:
        model = CarteTOTP


class TOTPDeviceFactory(factory.DjangoModelFactory):
    class Meta:
        model = TOTPDevice


class OrganisationTypeFactory(factory.DjangoModelFactory):
    name = "Type par défaut"

    class Meta:
        model = OrganisationType


class AidantFactory(factory.DjangoModelFactory):
    username = factory.Faker("email")
    email = factory.SelfAttribute("username")
    password = factory.PostGenerationMethodCall("set_password", "<PASSWORD>")
    last_name = "Goneau"
    first_name = "Thierry"
    profession = "secrétaire"
    organisation = factory.SubFactory(OrganisationFactory)

    class Meta:
        model = get_user_model()

    @factory.post_generation
    def post(self, create, _, **kwargs):
        if not create:
            return
        if kwargs.get("with_otp_device", False):
            device = self.staticdevice_set.create(id=self.id)
            device.token_set.create(token="<PASSWORD>")

        if kwargs.get("is_organisation_manager", False):
            self.responsable_de.add(self.organisation)


class HabilitationRequestFactory(factory.DjangoModelFactory):
    first_name = "Jean"
    last_name = "Dupont"
    email = factory.Faker("email")
    organisation = factory.SubFactory(OrganisationFactory)
    profession = "Secrétaire"

    class Meta:
        model = HabilitationRequest


class UsagerFactory(factory.DjangoModelFactory):
    given_name = "Homer"
    family_name = "Simpson"
    birthdate = "1902-06-30"
    gender = Usager.GENDER_MALE
    birthplace = "27681"
    birthcountry = Usager.BIRTHCOUNTRY_FRANCE
    email = "<EMAIL>"
    sub = factory.Sequence(lambda n: f"avalidsub{n}")

    class Meta:
        model = Usager


class MandatFactory(factory.DjangoModelFactory):
    organisation = factory.SubFactory(OrganisationFactory)
    usager = factory.SubFactory(UsagerFactory)
    creation_date = factory.LazyAttribute(lambda f: now())
    duree_keyword = "SHORT"
    expiration_date = factory.LazyAttribute(lambda f: now() + timedelta(days=1))

    class Meta:
        model = Mandat

    @factory.post_generation
    def post(self, create, _, **kwargs):
        authorisations = kwargs.get("create_authorisations", None)
        if not create or not isinstance(authorisations, Iterable):
            return

        for auth in authorisations:
            Autorisation.objects.create(
                mandat=self,
                demarche=str(auth),
                revocation_date=None,
            )


class ExpiredMandatFactory(MandatFactory):
    expiration_date = factory.LazyAttribute(lambda f: now() - timedelta(days=365))


class AutorisationFactory(factory.DjangoModelFactory):
    demarche = "justice"
    mandat = factory.SubFactory(MandatFactory)
    revocation_date = None

    class Meta:
        model = Autorisation


class LegacyAutorisationFactory(AutorisationFactory):
    # Used to test the migration script that actually *creates* mandats ^^
    mandat = None

    class Meta:
        model = Autorisation


class ConnectionFactory(factory.DjangoModelFactory):
    class Meta:
        model = Connection


class JournalFactory(factory.DjangoModelFactory):
    class Meta:
        model = Journal

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        creation_date = kwargs.pop("creation_date", None)
        obj = super(JournalFactory, cls)._create(model_class, *args, **kwargs)
        if creation_date is not None:
            Journal.objects.filter(pk=obj.pk).update(creation_date=creation_date)
        return obj


class AttestationJournalFactory(JournalFactory):
    action = "create_attestation"
    is_remote_mandat = False
    access_token = factory.Faker("md5")
    duree = 6


class DatavizRegionFactory(factory.DjangoModelFactory):
    class Meta:
        model = DatavizRegion


class DatavizDepartmentFactory(factory.DjangoModelFactory):
    class Meta:
        model = DatavizDepartment


class DatavizDepartmentsToRegionFactory(factory.DjangoModelFactory):
    class Meta:
        model = DatavizDepartmentsToRegion
