from __future__ import annotations

import datetime
import json
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any, TypeVar, cast
from uuid import UUID

from attrs import define as _attrs_define
from attrs import field as _attrs_field
from dateutil.parser import isoparse

from .. import types
from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.group import Group


T = TypeVar("T", bound="InviteLink")


@_attrs_define
class InviteLink:
    """Adds nested create feature

    Attributes:
        uuid (UUID):
        group (Group): Moves `UniqueValidator`'s from the validation stage to the save stage.
            It solves the problem with nested validation for unique fields on update.

            If you want more details, you can read related issues and articles:
            https://github.com/beda-software/drf-writable-nested/issues/1
            http://www.django-rest-framework.org/api-guide/validators/#updating-nested-serializers

            Example of usage:
            ```
                class Child(models.Model):
                field = models.CharField(unique=True)


            class Parent(models.Model):
                child = models.ForeignKey('Child')


            class ChildSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
                class Meta:
                    model = Child


            class ParentSerializer(NestedUpdateMixin, serializers.ModelSerializer):
                child = ChildSerializer()

                class Meta:
                    model = Parent
            ```

            Note: `UniqueFieldsMixin` must be applied only on the serializer
            which has unique fields.

            Note: When you are using both mixins
            (`UniqueFieldsMixin` and `NestedCreateMixin` or `NestedUpdateMixin`)
            you should put `UniqueFieldsMixin` ahead.
        used_by (int | None):
        created_by (int):
        created_at (datetime.datetime):
        id (int | Unset):
        email (str | Unset):
        valid_until (datetime.date | Unset):
        reusable (bool | Unset):
        internal_note (None | str | Unset):
    """

    uuid: UUID
    group: Group
    used_by: int | None
    created_by: int
    created_at: datetime.datetime
    id: int | Unset = UNSET
    email: str | Unset = UNSET
    valid_until: datetime.date | Unset = UNSET
    reusable: bool | Unset = UNSET
    internal_note: None | str | Unset = UNSET
    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> dict[str, Any]:
        uuid = str(self.uuid)

        group = self.group.to_dict()

        used_by: int | None
        used_by = self.used_by

        created_by = self.created_by

        created_at = self.created_at.isoformat()

        id = self.id

        email = self.email

        valid_until: str | Unset = UNSET
        if not isinstance(self.valid_until, Unset):
            valid_until = self.valid_until.isoformat()

        reusable = self.reusable

        internal_note: None | str | Unset
        if isinstance(self.internal_note, Unset):
            internal_note = UNSET
        else:
            internal_note = self.internal_note

        field_dict: dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "uuid": uuid,
                "group": group,
                "used_by": used_by,
                "created_by": created_by,
                "created_at": created_at,
            }
        )
        if id is not UNSET:
            field_dict["id"] = id
        if email is not UNSET:
            field_dict["email"] = email
        if valid_until is not UNSET:
            field_dict["valid_until"] = valid_until
        if reusable is not UNSET:
            field_dict["reusable"] = reusable
        if internal_note is not UNSET:
            field_dict["internal_note"] = internal_note

        return field_dict

    def to_multipart(self) -> types.RequestFiles:
        files: types.RequestFiles = []

        files.append(("uuid", (None, str(self.uuid), "text/plain")))

        files.append(("group", (None, json.dumps(self.group.to_dict()).encode(), "application/json")))

        if isinstance(self.used_by, int):
            files.append(("used_by", (None, str(self.used_by).encode(), "text/plain")))
        else:
            files.append(("used_by", (None, str(self.used_by).encode(), "text/plain")))

        files.append(("created_by", (None, str(self.created_by).encode(), "text/plain")))

        files.append(("created_at", (None, self.created_at.isoformat().encode(), "text/plain")))

        if not isinstance(self.id, Unset):
            files.append(("id", (None, str(self.id).encode(), "text/plain")))

        if not isinstance(self.email, Unset):
            files.append(("email", (None, str(self.email).encode(), "text/plain")))

        if not isinstance(self.valid_until, Unset):
            files.append(("valid_until", (None, self.valid_until.isoformat().encode(), "text/plain")))

        if not isinstance(self.reusable, Unset):
            files.append(("reusable", (None, str(self.reusable).encode(), "text/plain")))

        if not isinstance(self.internal_note, Unset):
            if isinstance(self.internal_note, str):
                files.append(("internal_note", (None, str(self.internal_note).encode(), "text/plain")))
            else:
                files.append(("internal_note", (None, str(self.internal_note).encode(), "text/plain")))

        for prop_name, prop in self.additional_properties.items():
            files.append((prop_name, (None, str(prop).encode(), "text/plain")))

        return files

    @classmethod
    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
        from ..models.group import Group

        d = dict(src_dict)
        uuid = UUID(d.pop("uuid"))

        group = Group.from_dict(d.pop("group"))

        def _parse_used_by(data: object) -> int | None:
            if data is None:
                return data
            return cast(int | None, data)

        used_by = _parse_used_by(d.pop("used_by"))

        created_by = d.pop("created_by")

        created_at = isoparse(d.pop("created_at"))

        id = d.pop("id", UNSET)

        email = d.pop("email", UNSET)

        _valid_until = d.pop("valid_until", UNSET)
        valid_until: datetime.date | Unset
        if isinstance(_valid_until, Unset):
            valid_until = UNSET
        else:
            valid_until = isoparse(_valid_until).date()

        reusable = d.pop("reusable", UNSET)

        def _parse_internal_note(data: object) -> None | str | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(None | str | Unset, data)

        internal_note = _parse_internal_note(d.pop("internal_note", UNSET))

        invite_link = cls(
            uuid=uuid,
            group=group,
            used_by=used_by,
            created_by=created_by,
            created_at=created_at,
            id=id,
            email=email,
            valid_until=valid_until,
            reusable=reusable,
            internal_note=internal_note,
        )

        invite_link.additional_properties = d
        return invite_link

    @property
    def additional_keys(self) -> list[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties
