import Foundation
import JSONCodable

/// {{ definition.description }}
{% if definition.properties | length == 0 and not definition.additionalProperties %}
public class {{ definition | modelType(spec) | raw }} {}
{% else %}
public class {{ definition | modelType(spec) | raw }} {

    {%~ for property in definition.properties %}
    /// {{ property.description }}
    public let {{ property.name | escapeSwiftKeyword | removeDollarSign }}: {{ property | propertyType(spec) | raw }}{% if not property.required %}?{% endif %}


    {%~ endfor %}
    {%~ if definition.additionalProperties %}
    /// Additional properties
    public let data: T
    {%~ endif %}

    init(
        {%~ for property in definition.properties %}
        {{ property.name | escapeSwiftKeyword | removeDollarSign }}: {{ property | propertyType(spec) | raw  }}{% if not property.required %}?{% endif %}{% if not loop.last or (loop.last and definition.additionalProperties) %},{% endif %}

        {%~ endfor %}
        {%~ if definition.additionalProperties %}
        data: T
        {%~ endif %}
    ) {
        {%~ for property in definition.properties %}
        self.{{ property.name | escapeSwiftKeyword | removeDollarSign }} = {{ property.name | escapeSwiftKeyword | removeDollarSign }}
        {%~ endfor %}
        {%~ if definition.additionalProperties %}
        self.data = data
        {%~ endif %}
    }

    public func toMap() -> [String: Any] {
        return [
            {%~ for property in definition.properties %}
            "{{ property.name | escapeSwiftKeyword }}": {% if property.sub_schema %}{% if property.type == 'array' %}{{property.name | escapeSwiftKeyword | removeDollarSign}}.map { $0.toMap() }{% else %}{{property.name | escapeSwiftKeyword | removeDollarSign}}.toMap(){% endif %}{% else %}{{property.name | escapeSwiftKeyword | removeDollarSign}}{% endif %} as Any{% if not loop.last or (loop.last and definition.additionalProperties) %},{% endif %}

            {%~ endfor %}
            {%~ if definition.additionalProperties %}
            "data": try! JSONEncoder().encode(data)
            {%~ endif %}
        ]
    }

    public static func from(map: [String: Any] ) -> {{ definition.name | caseUcfirst }} {
        return {{ definition.name | caseUcfirst }}(
            {%~ for property in definition.properties %}
            {{ property.name | escapeSwiftKeyword | removeDollarSign }}: {% if property.sub_schema %}{% if property.type == 'array' %}(map["{{property.name }}"] as! [[String: Any]]).map { {{property.sub_schema | caseUcfirst}}.from(map: $0) }{% else %}{{property.sub_schema | caseUcfirst}}.from(map: map["{{property.name }}"] as! [String: Any]){% endif %}{% else %}map["{{property.name }}"] as{% if property.required %}!{% else %}?{% endif %} {{ property | propertyType(spec) | raw }}{% endif %}{% if not loop.last or (loop.last and definition.additionalProperties) %},{% endif %}

            {%~ endfor %}
            {%~ if definition.additionalProperties %}
            data: try! JSONDecoder().decode(T.self, from: JSONSerialization.data(withJSONObject: map, options: []))
            {%~ endif %}
        )
    }
}
{% endif %}