{#- Django model template generator #}
{%- import "django_fields.py.j2" as django_fields -%}
from django.db import models

{# Enumeration definition -#}
{%- for enum in model.get_enumerations() %}
class {{ enum.name }}(models.TextChoices):
    {%- for literal in enum.literals %}
    {{ literal.name }} = '{{ literal.name }}', '{{ literal.name }}'
    {%- endfor %}
{% endfor -%}

{# Model definition #}
{%- for class_obj in model.classes_sorted_by_inheritance() %}
    {%- set generals = namespace(names=[]) %}
    {%- for parent in class_obj.parents() %}
        {%- set _ = generals.names.append(parent.name) %}
    {%- endfor %}
    {%- set inheritance = generals.names | join(', ') %}
class {{ class_obj.name }}({{ inheritance | default('models.Model', true) }}):
    """
    Represents a {{ class_obj.name[0].lower() + class_obj.name[1:] }} in the system.
    """
{%- for attr in sort_by_timestamp(class_obj.attributes) %}
    {{ attr.name }} = {{ django_fields.get_field(attr.type, model.get_enumerations()) }}{%- if not loop.last %}{% endif %}
{%- endfor %}
    {%- for end in class_obj.association_ends() -%}
        {%- set ns = namespace(opposite_end=end) %}
        {%- for end_assoc in end.owner.ends %}
            {%- if end_assoc != end %}
                {%- set ns.opposite_end = end_assoc %}
            {%- endif %}
        {%- endfor %}
    {# ManyToManyField in Django #}
    {%- if class_obj.name == many_to_many.get(end.owner.name) %}
    {{ end.name.replace(' ', '_') }} = models.ManyToManyField(
        '{{ end.type.name }}', related_name='{{ ns.opposite_end.name }}'{%- if end.multiplicity.min == 0 %}, blank=True{%- endif %})
    {%- endif -%}
    {# ForeignKey in Django #}
    {%- if class_obj.name == fkeys.get(end.owner.name) %}
    {{ end.name.replace(' ', '_') }} = models.ForeignKey(
        '{{ end.type.name }}', related_name='{{ ns.opposite_end.name }}', on_delete=models.{% if end.is_composite %}CASCADE
                {%- elif end.multiplicity.min == 0%}SET_NULL, blank=True, null=True{% else %}PROTECT{% endif %})
    {%- endif -%}
    {# OneToOneField in Django #}
    {%- if class_obj.name == one_to_one.get(end.owner.name) %}
    {{ end.name.replace(' ', '_') }} = models.OneToOneField(
        '{{ end.type.name }}', related_name='{{ ns.opposite_end.name }}', on_delete=models.{% if end.is_composite %}CASCADE
                {%- elif end.multiplicity.min == 0%}SET_NULL, blank=True, null=True{% else %}PROTECT{% endif %})
    {%- endif -%}
    {%- endfor %}

    class Meta:
        verbose_name = "{{ class_obj.name[0].upper() + class_obj.name[1:] }}"
        verbose_name_plural = "{{ class_obj.name[0].upper() + class_obj.name[1:] }}s"

    {%- set attr_primitive_data_type = [] %}
        {%- for attr in sort_by_timestamp(class_obj.attributes) %}
            {%- if attr.type is is_primitive_data_type %}
              {%- set _ = attr_primitive_data_type.append(attr) %}
            {%- endif %}
        {%- endfor %}
    {%- if attr_primitive_data_type %}
    {%- set first_attr = attr_primitive_data_type[0] %}

    def __str__(self):
        """
        Returns a string representation of the {{ class_obj.name[0].lower() + class_obj.name[1:] }}
        """
        return str(self.{{ first_attr.name }})

    {%- endif %}
{% endfor %}
