{% macro form_field(field, field_name, parent_id) %}
{%- set ns=namespace(minlength=False, maxlength=False, pattern=False) %}
{%- set required=field.is_required() %}
{%- if field.metadata %}
{%- for meta in field.metadata %}
    {%- if meta.min_length %}{% set ns.minlength=meta.min_length %}{% endif %}
    {%- if meta.max_length %}{% set ns.maxlength=meta.max_length %}{% endif %}
    {%- if meta.pattern %}{% set ns.pattern=meta.pattern %}{% endif %}
{%- endfor %}
{%- endif %}
{%- set closing_tag=False %}
{%- set input_type=None %}
{% if field.annotation.__args__ %}
  {% set annotation = field.annotation.__args__[0] %}
{% else %}
  {% set annotation = field.annotation %}
{% endif %}
{% set autocomplete=field.json_schema_extra.autocomplete %}
{%- if field.json_schema_extra and field.json_schema_extra.get('input_type', None) == 'textarea' %}
    {%- set element="textarea" %}
    {%- set closing_tag=True %}
    {%- set cls="form-textarea form-input" %}
{%- elif annotation.__members__ %}
    {%- set element="select" %}
    {%- set closing_tag=True %}
    {%- set cls="form-select form-input" %}
{%- elif annotation.__name__ == "bool" %}
    {%- set element="input" %}
    {%- set input_type="checkbox" %}
    {%- set checked=field.default is true %}
    {%- set cls="form-checkbox form-input" %}
{%- elif annotation.__name__ == "datetime"  %}
    {%- set element="input" %}
    {%- set input_type="datetime-local" %}
    {%- set cls="form-datetime form-input" %}
{%- else %}
    {%- set element="input" %}
    {%- set cls="form-input" %}
{%- endif -%}
<div class="form-input-group">
    <div class="constraint-gutter">
        <span class="error-feedback"></span>
        <span class="spacer"></span>
        <div class="constraints">
        {% if ns.minlength %}<span class="constraint">min length: {{ ns.minlength }}</span>{% endif %}
        {% if ns.maxlength %}<span class="constraint">max length: {{ ns.maxlength }}</span>{% endif %}
        {% if ns.pattern   %}<span class="constraint">matching: <code>{{ ns.pattern }}</code></span>{% endif %}
        {% if required     %}<span class="constraint">required</span>{% endif %}
        </div>
    </div>
{%- if field.json_schema_extra.input_type == "tokens" %}
    {{ token_input(field, field_name, parent_id) }}
{%- elif field.json_schema_extra.input_type == "model_list" %}
    <div class="model-list-input" name="{{ field_name }}">
    {{ add_subform_button(parent_id, field_name, 0, field.json_schema_extra.model_name) }}
    </div>
{% else %}
    <{{element}}
        id="{{ parent_id }}-{{ field_name }}"
        name="{{ field_name }}"
        class="{{ cls }}{% if not required %} optional{% endif %}"
        {%- if input_type %} type="{{ input_type }}"{% endif %}
        {%- if ns.minlength %} minlength="{{ ns.minlength }}"{% endif %}
        {%- if ns.maxlength %} maxlength="{{ ns.maxlength }}"{% endif %}
        {%- if ns.pattern %} pattern="{{ ns.pattern }}"{% endif %}
        {%- if required %} required{% endif %}
        {%- if checked %} checked{% endif %}
        {%- if autocomplete %}
          hx-get="/autocomplete/{{ autocomplete }}"
          hx-target="#{{ parent_id }}-{{ field_name }}-autocomplete"
          hx-trigger="input changed delay:250ms"
          list="{{ parent_id }}-{{ field_name }}-autocomplete"
        {%- endif %}
    >
    {%- if element=="select" %}
    {% for member in field.annotation.__members__.values() %}
    <option value="{{ member.value }}">{{ member.value }}</option>
    {% endfor %}
    {%- endif %}
    {%- if closing_tag %}</{{element}}>{% endif %}
    {% if autocomplete %}<datalist id="{{ parent_id }}-{{ field_name }}-autocomplete"></datalist>{% endif %}
{% endif %}
</div>

{% if field.description or (annotation.__members__ and annotation.__annotations__) %}
<div class="form-item-description">
    {%- if annotation.__members__ and annotation.__annotations__ %}
    <details>
    <summary>Show/Hide Option Description</summary>
    <table class="enum-description">
        <tr>
            <th>Option</th>
            <th>Description</th>
        </tr>
    {%- for key, val in annotation.__annotations__.items() %}
    <tr>
        <td class="key"><span class="bold">{{ key }}</span></td>
        <td class="value">{{ val.__metadata__[-1] }}</td>
    </tr>
    {%- endfor %}
    </table>
    </details>
    {%- endif %}
    {% if field.description %}
    <p>
    {{ field.description }}
    </p>
    {% endif %}
</div>
{% endif %}
{% endmacro %}

{% macro token_input(field, field_name, parent_id) %}
<div class="tokens-container" id="{{ parent_id }}-{{ field_name }}-tokens"></div>
<input
    class="form-input form-tokens"
    id="{{ parent_id }}-{{ field_name }}"
    name="{{ field_name }}"
    list="{{ parent_id }}-{{ field_name }}-autocomplete"
    hx-get="/autocomplete/{{ field_name }}"
    hx-target="#{{ parent_id }}-{{ field_name }}-autocomplete"
    hx-trigger="input changed delay:250ms"
    hx-params="*"
    data-tokens-container="#{{ parent_id }}-{{ field_name }}-tokens"
>
<datalist id="{{ parent_id }}-{{ field_name }}-autocomplete"></datalist>
{% endmacro %}

{% macro add_subform_button(parent_id, field_name, idx, model_name) %}
<a class="add-subform-button button"
   hx-get="/partials/model-list?idx={{idx}}&field_name={{field_name}}&model_name={{model_name}}&form_id={{parent_id}}"
   hx-swap="outerHTML"
>
    +
</a>
{% endmacro %}

{% macro inner_model_form(id, model, exclude = []) %}
{% for field_name, field in model.model_fields.items() if field_name not in exclude %}
{% if not field.json_schema_extra or field.json_schema_extra and field.json_schema_extra.get('input_type', None) != 'none' %}
<div class="form-item" data-field-name="{{ field_name }}">
    <label for="{{ id }}-{{ field_name }}" class="form-label">
        {% if field.title %}
            {{ field.title }}
        {% else %}
            {{ field_name }}
        {% endif %}
    </label>
    {{ form_field(field, field_name, id) }}
</div>
{% else %}
{% endif %}
{% endfor %}
{% endmacro %}

{% macro model_form(id, model, exclude = []) %}
<form class="form" id="{{ id }}" hx-ext="form-json">
  {{ inner_model_form(id, model, exclude) }}
</form>
{% endmacro %}