{%- macro encode_value(source, encodable, depth) -%}
  {%- if encodable.is_nullable -%}
    @Nullable {{encode_value(source, encodable.without_nullable(), depth + 1)}}
  {%- elif encodable.is_optional -%}
    Optional<{{encode_value(source, encodable.without_optional(), depth + 1)}}>
  {%- elif encodable.is_list -%}
    ArrayList<{{encode_value(source, encodable.without_list(), depth + 1)}}>
  {%- elif encodable.is_struct -%}
    {%- set struct = encodable.get_underlying_struct() -%}
    ChipStructs.{{source.name}}Cluster{{struct.name}}
  {%- else -%}
    {{encodable.boxed_java_type}}
  {%- endif -%}
{%- endmacro -%}

{%- macro encode_value_remove_generic(source, encodable, depth) -%}
  {%- if encodable.is_optional -%}
    Optional
  {%- elif encodable.is_list -%}
    ArrayList
  {%- elif encodable.is_struct -%}
    {%- set struct = encodable.get_underlying_struct() -%}
    ChipStructs.{{source.name}}Cluster{{struct.name}}
  {%- else -%}
    {{encodable.boxed_java_type}}
  {%- endif -%}
{%- endmacro -%}

{%- macro encode_value_remove_generic_optional(source, encodable, depth) -%}
  {%- if encodable.is_list -%}
    ArrayList
  {%- elif encodable.is_struct -%}
    {%- set struct = encodable.get_underlying_struct() -%}
    ChipStructs.{{source.name}}Cluster{{struct.name}}
  {%- else -%}
    {{encodable.boxed_java_type}}
  {%- endif -%}
{%- endmacro -%}

{%- macro encode_value_without_optional(source, encodable, depth) -%}
  {%- if encodable.is_nullable -%}
    @Nullable {{encode_value_without_optional(source, encodable.without_nullable(), depth + 1)}}
  {%- elif encodable.is_list -%}
    List<{{encode_value_without_optional(source, encodable.without_list(), depth + 1)}}>
  {%- elif encodable.is_struct -%}
    {%- set struct = encodable.get_underlying_struct() -%}
    ChipStructs.{{source.name}}Cluster{{struct.name}}
  {%- else -%}
    {{encodable.boxed_java_type}}
  {%- endif -%}
{%- endmacro -%}

{%- macro encode_value_without_nullable_arraylist(source, encodable, depth) -%}
{%- if encodable.is_optional -%}
    Optional<{{encode_value_without_nullable_arraylist(source, encodable.without_optional(), depth + 1)}}>
  {%- elif encodable.is_list -%}
    ArrayList<{{encode_value_without_nullable_arraylist(source, encodable.without_list(), depth + 1)}}>
  {%- elif encodable.is_struct -%}
    {%- set struct = encodable.get_underlying_struct() -%}
    ChipStructs.{{source.name}}Cluster{{struct.name}}
  {%- else -%}
    {{encodable.boxed_java_type}}
  {%- endif -%}
{%- endmacro -%}

{%- macro encode_value_without_optional_nullable(source, encodable, depth) -%}
  {%- if encodable.is_list -%}
    List<{{encode_value_without_optional_nullable(source, encodable.without_list(), depth + 1)}}>
  {%- elif encodable.is_struct -%}
    {%- set struct = encodable.get_underlying_struct() -%}
    ChipStructs.{{source.name}}Cluster{{struct.name}}
  {%- else -%}
    {{encodable.boxed_java_type}}
  {%- endif -%}
{%- endmacro -%}

/*
 *
 *    Copyright (c) 2023 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package chip.devicecontroller;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;
import chip.clusterinfo.ClusterInfo;
import chip.clusterinfo.InteractionInfo;
import chip.clusterinfo.CommandParameterInfo;
import chip.clusterinfo.DelegatedClusterCallback;
import chip.clusterinfo.ClusterCommandCallback;
import chip.clusterinfo.CommandResponseInfo;
import chip.devicecontroller.ChipClusters.DefaultClusterCallback;
import chip.devicecontroller.ClusterReadMapping;
import chip.devicecontroller.ClusterWriteMapping;

public class ClusterInfoMapping {

  public static class DelegatedCharStringAttributeCallback implements ChipClusters.CharStringAttributeCallback, DelegatedClusterCallback {
    /** Indicates a successful read for a CHAR_STRING attribute. */
    private ClusterCommandCallback callback;

    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    @Override
    public void onSuccess(String value) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      CommandResponseInfo setupPINResponseValue = new CommandResponseInfo("value", "String");
      responseValues.put(setupPINResponseValue, value);
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception error) {
      callback.onFailure(error);
    }
  }

  public static class DelegatedOctetStringAttributeCallback implements ChipClusters.OctetStringAttributeCallback, DelegatedClusterCallback {
    /** Indicates a successful read for an OCTET_STRING attribute. */
    private ClusterCommandCallback callback;

    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    @Override
    public void onSuccess(byte[] value) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      CommandResponseInfo setupPINResponseValue = new CommandResponseInfo("value", "byte[]");
      responseValues.put(setupPINResponseValue, value);
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception error) {
      callback.onFailure(error);
    }
  }

  public static class DelegatedIntegerAttributeCallback implements ChipClusters.IntegerAttributeCallback, DelegatedClusterCallback {
    private ClusterCommandCallback callback;

    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    @Override
    public void onSuccess(int value) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      CommandResponseInfo setupPINResponseValue = new CommandResponseInfo("value", "int");
      responseValues.put(setupPINResponseValue, value);
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception error) {
      callback.onFailure(error);
    }
  }

  public static class DelegatedLongAttributeCallback implements ChipClusters.LongAttributeCallback, DelegatedClusterCallback {
    private ClusterCommandCallback callback;

    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    @Override
    public void onSuccess(long value) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      CommandResponseInfo setupPINResponseValue = new CommandResponseInfo("value", "long");
      responseValues.put(setupPINResponseValue, value);
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception error) {
      callback.onFailure(error);
    }
  }

  public static class DelegatedBooleanAttributeCallback implements ChipClusters.BooleanAttributeCallback, DelegatedClusterCallback {
    private ClusterCommandCallback callback;

    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    @Override
    public void onSuccess(boolean value) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      CommandResponseInfo setupPINResponseValue = new CommandResponseInfo("value", "boolean");
      responseValues.put(setupPINResponseValue, value);
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception error) {
      callback.onFailure(error);
    }
  }

  public static class DelegatedFloatAttributeCallback implements ChipClusters.FloatAttributeCallback, DelegatedClusterCallback {
    private ClusterCommandCallback callback;

    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    @Override
    public void onSuccess(float value) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      CommandResponseInfo setupPINResponseValue = new CommandResponseInfo("value", "float");
      responseValues.put(setupPINResponseValue, value);
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception error) {
      callback.onFailure(error);
    }
  }

  public static class DelegatedDoubleAttributeCallback implements ChipClusters.DoubleAttributeCallback, DelegatedClusterCallback {
    private ClusterCommandCallback callback;

    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    @Override
    public void onSuccess(double value) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      CommandResponseInfo setupPINResponseValue = new CommandResponseInfo("value", "double");
      responseValues.put(setupPINResponseValue, value);
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception error) {
      callback.onFailure(error);
    }
  }

  public static class DelegatedDefaultClusterCallback implements DefaultClusterCallback, DelegatedClusterCallback {
    private ClusterCommandCallback callback;

    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    // Parameters and list-adds here should be generated - refer to the template code that creates each callback interface.
    @Override
    public void onSuccess() {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception e) {
      callback.onFailure(e);
    }
  }
{% for cluster in clientClusters | sort(attribute='code') -%}
{%- set typeLookup = idl | createLookupContext(cluster) -%}
{%- set already_handled_command = [] -%}
{% for command in cluster.commands | sort(attribute='code') -%}
{% if command | isCommandNotDefaultCallback() -%}
{% set callbackName = command | javaCommandCallbackName() -%}
{%- if callbackName not in already_handled_command %}

  public static class Delegated{{cluster.name}}Cluster{{callbackName}}Callback implements ChipClusters.{{cluster.name}}Cluster.{{callbackName}}Callback, DelegatedClusterCallback {
    private ClusterCommandCallback callback;
    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    @Override
    public void onSuccess(
{%- for field in (cluster.structs | named(command.output_param)).fields -%}
{%- set encodable = field | asEncodable(typeLookup) -%}
      {{encode_value(cluster, encodable, 0)}} {{field.name}}
      {%- if loop.index0 < loop.length - 1 -%}{{", "}}{%- endif -%}
{%- endfor -%}) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
{% for field in (cluster.structs | named(command.output_param)).fields -%}
{%- set encodable = field | asEncodable(typeLookup) -%}
{% if encodable.is_list %}
      // {{field.name}}: {{encodable.data_type.name}}
      // Conversion from this type to Java is not properly implemented yet
{% else -%}
{%- if encodable.is_struct -%}
{%- set struct = encodable.get_underlying_struct() %}
      // {{field.name}}: Struct {{struct.name}}
      // Conversion from this type to Java is not properly implemented yet
{%- else %}
      CommandResponseInfo {{field.name}}ResponseValue = new CommandResponseInfo("{{field.name}}", "{{encode_value_without_nullable_arraylist(cluster, encodable, 0)}}");
      responseValues.put({{field.name}}ResponseValue, {{field.name}});
{%- endif -%}
{%- endif -%}
{% endfor %}
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception error) {
      callback.onFailure(error);
    }
  }
{%- if already_handled_command.append(callbackName) -%}
{# This block does nothing, it only exists to append to already_handled_command. #}
{%- endif -%}
{%- endif -%}
{%- endif -%}
{% endfor %}

{%- set already_handled_attribute = [] -%}
{%- for attribute in cluster.attributes | rejectattr('definition', 'is_field_global_name', typeLookup) -%}
{%- set encodable = attribute.definition | asEncodable(typeLookup) -%}
{%- set encodable2 = attribute.definition | asEncodable(typeLookup) -%}
{%- set encodable_check = attribute.definition | asEncodable(typeLookup) -%}
{%- set interfaceName = attribute | javaAttributeCallbackName(typeLookup) -%}
{%- if interfaceName not in already_handled_attribute %}
  public static class Delegated{{cluster.name}}Cluster{{attribute.definition.name | upfirst}}AttributeCallback implements ChipClusters.{{cluster.name}}Cluster.{{attribute.definition.name | upfirst}}AttributeCallback, DelegatedClusterCallback {
    private ClusterCommandCallback callback;
    @Override
    public void setCallbackDelegate(ClusterCommandCallback callback) {
      this.callback = callback;
    }

    {# NOTE: asJavaType ends up sniffing for isArray on the context. Since we want the type of our _entry_, force isArray to false. -#}
    @Override
    public void onSuccess({{encode_value_without_optional(cluster, encodable, 0)}} {% if encodable_check.is_list -%}valueList{%- else -%}value{%- endif -%}) {
      Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
      CommandResponseInfo commandResponseInfo = new CommandResponseInfo("{%- if encodable_check.is_list -%}valueList{%- else -%}value{%- endif -%}", "{{encode_value_without_optional_nullable(cluster, encodable2, 0)}}");
      responseValues.put(commandResponseInfo, {% if encodable_check.is_list -%}valueList{%- else -%}value{%- endif -%});
      callback.onSuccess(responseValues);
    }

    @Override
    public void onError(Exception ex) {
      callback.onFailure(ex);
    }
  }
{% if already_handled_attribute.append(interfaceName) -%}
{# This block does nothing, it only exists to append to already_handled_attribute. #}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endfor %}

  public Map<String, ClusterInfo> getClusterMap() {
    Map<String, ClusterInfo> clusterMap = initializeClusterMap();
    Map<String, Map<String, InteractionInfo>> commandMap = getCommandMap();
    combineCommand(clusterMap, commandMap);
    Map<String, Map<String, InteractionInfo>> readAttributeMap = new ClusterReadMapping().getReadAttributeMap();
    combineCommand(clusterMap, readAttributeMap);
    Map<String, Map<String, InteractionInfo>> writeAttributeMap = new ClusterWriteMapping().getWriteAttributeMap();
    combineCommand(clusterMap, writeAttributeMap);
    return clusterMap;
 }

  public Map<String, ClusterInfo> initializeClusterMap() {
    Map<String, ClusterInfo> clusterMap = new HashMap<>();
{% for cluster in clientClusters | sort(attribute='code') %}
    ClusterInfo {{cluster.name | lowfirst}}ClusterInfo = new ClusterInfo(
      (ptr, endpointId) -> new ChipClusters.{{cluster.name}}Cluster(ptr, endpointId), new HashMap<>());
    clusterMap.put("{{cluster.name | lowfirst}}", {{cluster.name | lowfirst}}ClusterInfo);
{% endfor %}
    return clusterMap;
  }

  public void combineCommand(Map<String, ClusterInfo> destination, Map<String, Map<String, InteractionInfo>> source) {
{%- for cluster in clientClusters | sort(attribute='code') %}
    destination.get("{{cluster.name | lowfirst}}").combineCommands(source.get("{{cluster.name | lowfirst}}"));
{%- endfor %}
  }

 @SuppressWarnings("unchecked")
  public Map<String, Map<String, InteractionInfo>> getCommandMap() {
    Map<String, Map<String, InteractionInfo>> commandMap = new HashMap<>();
{% for cluster in clientClusters | sort(attribute='code') -%}
{%- set typeLookup = idl | createLookupContext(cluster) %}
    Map<String, InteractionInfo> {{cluster.name | lowfirst}}ClusterInteractionInfoMap = new LinkedHashMap<>();
{% for command in cluster.commands | sort(attribute='code') -%}
{%- set callbackName = command | javaCommandCallbackName() %}
    Map<String, CommandParameterInfo> {{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}CommandParams = new LinkedHashMap<String, CommandParameterInfo>();
    {#- TODO: fill out parameter types -#}
{%- if command.input_param -%}
{%- for field in (cluster.structs | named(command.input_param)).fields -%}
{%- set encodable = field | asEncodable(typeLookup) %}
{% if not encodable.is_struct %}
    CommandParameterInfo {{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}{{field.name | lowfirst_except_acronym}}CommandParameterInfo = new CommandParameterInfo("{{field.name | lowfirst_except_acronym}}", {{encode_value_remove_generic(cluster, encodable, 0)}}.class, {{encode_value_remove_generic_optional(cluster, encodable, 0)}}.class);
    {{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}CommandParams.put("{{field.name | lowfirst_except_acronym}}",{{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}{{field.name | lowfirst_except_acronym}}CommandParameterInfo);
{%- endif -%}
{% endfor -%}
{%- endif -%}

{% if command | isCommandNotDefaultCallback() %}
    InteractionInfo {{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}InteractionInfo = new InteractionInfo(
      (cluster, callback, commandArguments) -> {
        ((ChipClusters.{{cluster.name}}Cluster) cluster)
          .{{command.name | lowfirst_except_acronym}}((ChipClusters.{{cluster.name}}Cluster.{{callbackName}}Callback) callback
{%- if command.input_param -%}
{% for field in (cluster.structs | named(command.input_param)).fields -%}
{%- set encodable = field | asEncodable(typeLookup) %}
           , ({{encode_value_without_nullable_arraylist(cluster, encodable, 0)}})
             commandArguments.get("{{field.name | lowfirst_except_acronym}}")
{% endfor -%}
{%- endif %}
            {# TODO: Allow timeout to be passed from client for this and timed write. -#}
            {%- if command.is_timed_invoke -%}, 10000{%- endif -%}
          );
        },
        () -> new Delegated{{cluster.name}}Cluster{{callbackName}}Callback(),
        {{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}CommandParams
      );
{%- else %}
    InteractionInfo {{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}InteractionInfo = new InteractionInfo(
      (cluster, callback, commandArguments) -> {
        ((ChipClusters.{{cluster.name}}Cluster) cluster)
        .{{command.name | lowfirst_except_acronym}}((DefaultClusterCallback) callback
{%- if command.input_param %}
{%- for field in (cluster.structs | named(command.input_param)).fields -%}
{%- set encodable = field | asEncodable(typeLookup) %}
        , ({{encode_value_without_nullable_arraylist(cluster, encodable, 0)}})
        commandArguments.get("{{field.name | lowfirst_except_acronym}}")
{%- endfor -%}
{%- endif -%}
        {#- TODO: Allow timeout to be passed from client for this and timed write. -#}
        {% if command.is_timed_invoke %}, 10000{%- endif %}
        );
      },
      () -> new DelegatedDefaultClusterCallback(),
        {{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}CommandParams
    );
{%- endif %}
    {{cluster.name | lowfirst}}ClusterInteractionInfoMap.put("{{command.name | lowfirst_except_acronym}}", {{cluster.name | lowfirst}}{{command.name | lowfirst_except_acronym}}InteractionInfo);
{% endfor %}
    commandMap.put("{{cluster.name | lowfirst}}", {{cluster.name | lowfirst}}ClusterInteractionInfoMap);
{% endfor %}
    return commandMap;
  }
}
