{% template ClientFileHeader %}
{% template ReactQuery.Imports %}
import { trimArrayEnd, isParameterObject, getBaseUrl, addMetaToOptions } from './helpers';
{% template ReactQuery.MetaFile %}
{% template ReactQuery.GetClientFunction %}
{%- if Framework.IsAxios -%}
import type { AxiosRequestConfig } from 'axios';
{%- endif -%}

{%- if HasOperations -%}
{%- assign QueryClassName = Class | prepend: 'Qqqqqq' | slice: 0, Class.size | append: "Query" | slice: 6, 1000 -%}
{%- assign MutationClassName = Class | prepend: 'Qqqqqq' | slice: 0, Class.size | append: "Mutation" | slice: 6, 1000 -%}

{%- for operation in Operations -%}
{%-   assign GetWithBody = operation.HttpMethodUpper == 'Get' and operation.Parameters.size > 0 -%}
{%-   assign AddQueryForNonGetOperation = false -%}{%- assign AddQueryForNonGetOperationCondition = 'false' -%}{%-   if AddQueryForNonGetOperationCondition == "true" -%}{%-assign AddQueryForNonGetOperation = true -%}{%- endif -%}
{%-   assign NonBodyParameters = operation.PathParameters | concat: operation.QueryParameters | concat: operation.HeaderParameters %}
{%-   if NonBodyParameters.size > 0 or AddQueryForNonGetOperation or GetWithBody   -%}
{%-     assign firstLetter = operation.ActualOperationName | slice: 0, 1 | upcase -%}
{%-     assign parameterClassName = operation.ActualOperationName | append: 'q' | slice: 1, operation.ActualOperationName.size | prepend: firstLetter | slice: 0, operation.ActualOperationName.size | append: QueryClassName | append: 'Parameters' -%}
export type {{ parameterClassName }} = {
  {%-   for parameter in operation.Parameters -%}
{%- assign NotIsBody = true -%}{%- if parameter.IsBody -%}{%- assign NotIsBody = false -%}{%- endif -%}
  {%-       if NotIsBody or AddQueryForNonGetOperation or GetWithBody -%}
  {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %}?{% endif %}: Types.{{ parameter.Type }}{{ parameter.TypePostfix }} ;{% comment %}space before the ';' is important, so that 'undefined' here is not replaced with null{% endcomment %}
  {%-       endif -%}
  {%-   endfor -%}
}

{%- endif -%}
{%- if operation.HttpMethodUpper <> 'Get' -%}
{%- if operation.FormParameters.size > 0 -%}
{%- assign firstLetter = operation.ActualOperationName | slice: 0, 1 | upcase -%}
{%- assign parameterClassName = operation.ActualOperationName | append: 'q' | slice: 1, operation.ActualOperationName.size | prepend: firstLetter | slice: 0, operation.ActualOperationName.size | append: MutationClassName | append: 'Parameters' -%}
export type {{ parameterClassName }} = {
  {%- for parameter in operation.FormParameters -%}
  {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %}?{% endif %}: Types.{{ parameter.Type }}{{ parameter.TypePostfix }} ;{% comment %}space before the ';' is important, so that 'undefined' here is not replaced with null{% endcomment %}
  {%- endfor -%}
}

{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- for operation in Operations -%}
{%-   assign firstLetter = operation.ActualOperationName | slice: 0, 1 | upcase -%}
{%-   assign parameterClassName = operation.ActualOperationName | append: 'q' | slice: 1, operation.ActualOperationName.size | prepend: firstLetter | slice: 0, operation.ActualOperationName.size | append: QueryClassName | append: 'Parameters' -%}
{%-   assign ResultType = operation.ResultType | prepend: 'Types.' -%}
{%-   assign firstLetter = operation.ActualOperationName | slice: 0, 1 | upcase -%}
{%-   assign NonBodyParameters = operation.PathParameters | concat: operation.QueryParameters | concat: operation.HeaderParameters %}
export function {{ operation.ActualOperationName }}Url({% for parameter in NonBodyParameters %}{{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %}?{% endif %}: {{ parameter.Type | prepend: 'Types.' }}{{ parameter.TypePostfix }}{% unless forloop.last %}, {% endunless -%}{% endfor %}): string {
  {% template Client.RequestUrl %}
  return url_;
}

{%- if operation.HttpMethodUpper <> 'Get' -%}
    {%- assign firstLetter = operation.ActualOperationName | slice: 0, 1 | upcase -%}
    {%- if operation.FormParameters.size > 0 -%}
      {%- assign TVariableType = operation.ActualOperationName | append: 'q' | slice: 1, operation.ActualOperationName.size | prepend: firstLetter | slice: 0, operation.ActualOperationName.size | append: MutationClassName | append: 'Parameters' -%}
      {%- assign TVariableName = operation.ActualOperationName | append: MutationClassName | append: 'Parameters' -%}
    {%- else -%}
      {%- assign TVariableType = operation.ContentParameter.Type | default: 'void' | prepend: 'Types.' -%}
      {%- assign TVariableName = operation.ContentParameter.VariableName -%}
    {%- endif -%}
export function {{ operation.ActualOperationName }}MutationKey({%- for parameter in NonBodyParameters -%}{%- assign ParameterType = parameter.Type | prepend: 'Types.' -%}{{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %}?{% endif %}: {{ ParameterType }}{{ parameter.TypePostfix }}{% unless forloop.last %}, {% endunless -%}{%- endfor -%}): MutationKey {
  return trimArrayEnd([
      '{{ Class }}',
      '{{ operation.ActualOperationName }}',
      {%- for parameter in NonBodyParameters -%}
      {{ parameter.VariableName }} as any,
      {%- endfor -%}
    ]);
}

{% template Client.Method.Documentation %}
export function {{ operation.MethodAccessModifier }}use{{ operation.ActualOperationName | capitalize }}Mutation<TContext>({%- for parameter in NonBodyParameters -%}{%- assign ParameterType = parameter.Type | prepend: 'Types.' -%}{{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %}?{% endif %}: {{ ParameterType }}{{ parameter.TypePostfix }}, {% endfor -%}options?: Omit<UseMutationOptions<{{ ResultType }}, unknown, {{ TVariableType }}, TContext>, 'mutationKey' | 'mutationFn'>): UseMutationResult<{{ ResultType }}, unknown, {{ TVariableType }}, TContext> {
  const key = {{ operation.ActualOperationName }}MutationKey({%- for parameter in NonBodyParameters -%}{{ parameter.VariableName }}{% unless forloop.last %}, {% endunless -%}{% endfor -%});
  
  const metaContext = useContext(QueryMetaContext);
  options = addMetaToOptions(options, metaContext);
  
  {%- if operation.FormParameters.size > 0 -%}
  return useMutation({
    ...options,
    mutationFn: ({{TVariableName}}: {{TVariableType}}) => {% template ReactQuery.GetClientCall %}.{% template OperationNameSafe %}({%- for parameter in operation.Parameters -%}
      {%- assign isForm = false -%}
      {%- for formParameter in operation.FormParameters -%}
        {%- if parameter.Name == formParameter.Name -%}
          {%- assign isForm = true -%}
        {%- endif -%}
      {%- endfor -%}
      {%- if isForm %}{{TVariableName}}.{{parameter.VariableName}}{% else %}{{ parameter.VariableName }}{% endif %}{% unless forloop.last %}, {% endunless -%}{% endfor -%}),
    mutationKey: key,
  });
  {%- else -%}
  return useMutation({
    ...options,
    mutationFn: ({% if operation.HasBody %}{{TVariableName}}: {{TVariableType}}{% endif %}) => {% template ReactQuery.GetClientCall %}.{% template OperationNameSafe %}({%- for parameter in operation.Parameters -%}{%- assign ParameterType = parameter.Type -%}{{ parameter.VariableName }}{% unless forloop.last %}, {% endunless -%}{% endfor -%}),
    mutationKey: key,
  });
  {%- endif -%}
}
{%- if NonBodyParameters.size > 0 -%}
  {% assign TVariableTypeWithParameters = operation.ActualOperationName | capitalize | append: '__MutationParameters' %}
type {{ TVariableTypeWithParameters }} = {{ parameterClassName }}{%- if operation.HasBody %} & {
  {{ TVariableName }}: {{ TVariableType }};
}{% endif %}

{% template Client.Method.Documentation %}
export function {{ operation.MethodAccessModifier }}use{{ operation.ActualOperationName | capitalize }}MutationWithParameters<TContext>(options?: Omit<UseMutationOptions<{{ ResultType }}, unknown, {{ TVariableTypeWithParameters }}, TContext>, 'mutationKey' | 'mutationFn'> & { parameters?: {{ parameterClassName }}}): UseMutationResult<{{ ResultType }}, unknown, {{ TVariableTypeWithParameters }}, TContext> {
  const key = {{ operation.ActualOperationName }}MutationKey({%- for parameter in NonBodyParameters -%}options?.parameters?.{{ parameter.VariableName }}!{% unless forloop.last %}, {% endunless -%}{% endfor -%});
  
  const metaContext = useContext(QueryMetaContext);
  options = addMetaToOptions(options, metaContext);
  
  {%- if operation.FormParameters.size > 0 -%}
  return useMutation({
    ...options, 
    mutationFn: (data: {{ TVariableTypeWithParameters }}) => {% template ReactQuery.GetClientCall %}.{% template OperationNameSafe %}({%- for parameter in operation.Parameters -%}
      {%- assign isForm = false -%}
      {%- for formParameter in operation.FormParameters -%}
        {%- if parameter.Name == formParameter.Name -%}
          {%- assign isForm = true -%}
        {%- endif -%}
      {%- endfor -%}
      {%- if isForm %}data.{{parameter.VariableName}}{% else %}data.{{ parameter.VariableName }}{% endif %}{% unless forloop.last %}, {% endunless -%}{% endfor -%}),
    mutationKey: key,
  });
  {%- else -%}
return useMutation({
  ...options, 
  mutationFn: (data: {{ TVariableTypeWithParameters }}) => {% template ReactQuery.GetClientCall %}.{% template OperationNameSafe %}({%- for parameter in operation.Parameters -%}data.{{ parameter.VariableName }}{% unless parameter.IsBody %} ?? options?.parameters?.{{ parameter.VariableName }}!{% endunless %}{% unless forloop.last %}, {% endunless -%}{% endfor -%}),
  mutationKey: key,
});
  {%- endif -%}
}
{%- endif -%}
{%- endif -%}
{%-   assign AddQueryForNonGetOperation = false -%}{%- assign AddQueryForNonGetOperationCondition = 'false' -%}{%-   if AddQueryForNonGetOperationCondition == "true" -%}{%-assign AddQueryForNonGetOperation = true -%}{%- endif -%}
{%- if operation.HttpMethodUpper == 'Get' or AddQueryForNonGetOperation -%}
    {%- assign parameterClassName = operation.ActualOperationName | append: 'q' | slice: 1, operation.ActualOperationName.size | prepend: firstLetter | slice: 0, operation.ActualOperationName.size | append: QueryClassName | append: 'Parameters' -%}
let {{ operation.ActualOperationName }}DefaultOptions: Omit<UseQueryOptions<{{ ResultType }}, unknown, {{ ResultType }}>, 'queryKey' | 'queryFn'> & Partial<Pick<UseQueryOptions<{{ ResultType }}, unknown, {{ ResultType }}>, 'queryFn'>> = {
};
export function get{{ operation.ActualOperationName | capitalize }}DefaultOptions() {
  return {{ operation.ActualOperationName }}DefaultOptions;
};
export function set{{ operation.ActualOperationName | capitalize }}DefaultOptions(options: typeof {{ operation.ActualOperationName }}DefaultOptions) {
  {{ operation.ActualOperationName }}DefaultOptions = options;
}

{%- if operation.Parameters.size > 1 -%}
export function {{ operation.ActualOperationName }}QueryKey(dto: {{ parameterClassName }}): QueryKey;
{%- endif -%}
export function {{ operation.ActualOperationName }}QueryKey({%- for parameter in operation.Parameters -%}{%- assign ParameterType = parameter.Type | prepend: 'Types.' -%}{{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %}?{% endif %}: {{ ParameterType }}{{ parameter.TypePostfix }}{% unless forloop.last %}, {% endunless -%}{%- endfor -%}): QueryKey;
export function {{ operation.ActualOperationName }}QueryKey(...params: any[]): QueryKey {
    {%- if operation.Parameters.size == 0 -%}
  return trimArrayEnd([
      '{{ Class }}',
      '{{ operation.ActualOperationName }}',
    ]);
    {%- else -%}
  if (params.length === 1 && isParameterObject(params[0])) {
    const { {% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %} } = params[0] as {{ parameterClassName  }};

    return trimArrayEnd([
        '{{ Class }}',
        '{{ operation.ActualOperationName }}',
        {%- for parameter in operation.Parameters -%}
        {{ parameter.VariableName }} as any,
        {%- endfor -%}
      ]);
  } else {
    return trimArrayEnd([
        '{{ Class }}',
        '{{ operation.ActualOperationName }}',
        ...params
      ]);
  }
    {%- endif -%}
}
{%- comment -%} Why add __ to the function name? see below where it's used {%- endcomment -%}
export function __{{ operation.ActualOperationName }}(context: QueryFunctionContext{%- if Framework.IsAxios -%}, axiosConfig?: AxiosRequestConfig | undefined{%- endif -%}) {
  return {% template ReactQuery.GetClientCall %}.{% template OperationNameSafe %}(
  {%- for parameter in operation.Parameters -%}
{%- assign ParameterType = parameter.Type | prepend: 'Types.' -%}
      context.queryKey[{{ forloop.index | plus: 1  }}] as {{ ParameterType }}{{ parameter.TypePostfix }}{% unless forloop.last %}, {% endunless -%}
  {%- endfor -%}{%- if Framework.IsAxios -%}{% if operation.Parameters.size > 0 %}, {%- endif -%}axiosConfig{%- endif -%}
    );
}

    {%- if operation.Parameters.size > 0 -%}
export function {{ operation.MethodAccessModifier }}use{{ operation.ActualOperationName | capitalize }}Query<TSelectData = {{ ResultType }}, TError = unknown>(dto: {{ parameterClassName }}, options?: Omit<UseQueryOptions<{{ ResultType }}, TError, TSelectData>, 'queryKey'>{%- if Framework.IsAxios %}, axiosConfig?: Partial<AxiosRequestConfig>{% endif %}): UseQueryResult<TSelectData, TError>;
    {%- endif -%}
{% template Client.Method.Documentation %}
export function {{ operation.MethodAccessModifier }}use{{ operation.ActualOperationName | capitalize }}Query<TSelectData = {{ ResultType }}, TError = unknown>({%- for parameter in operation.Parameters -%}{%- assign ParameterType = parameter.Type | prepend: 'Types.' -%}{{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %}?{% endif %}: {{ ParameterType }}{{ parameter.TypePostfix }}, {% endfor %}options?: Omit<UseQueryOptions<{{ ResultType }}, TError, TSelectData>, 'queryKey'>{%- if Framework.IsAxios %}, axiosConfig?: Partial<AxiosRequestConfig>{% endif %}): UseQueryResult<TSelectData, TError>;
export function use{{ operation.ActualOperationName | capitalize }}Query<TSelectData = {{ ResultType }}, TError = unknown>(...params: any []): UseQueryResult<TSelectData, TError> {
  let options: UseQueryOptions<{{ ResultType }}, TError, TSelectData> | undefined = undefined;
  {%- if Framework.IsAxios -%}
  let axiosConfig: AxiosRequestConfig |undefined = undefined;
  {%- endif -%}
  {% for parameter in operation.Parameters %}let {{ parameter.VariableName }}: any = undefined;
  {% endfor %}
{%- if operation.Parameters.size > 0 -%}
  if (params.length > 0) {
    if (isParameterObject(params[0])) {
      ({ {% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %} } = params[0] as {{ parameterClassName  }});
      options = params[1];
      {%- if Framework.IsAxios -%}
      axiosConfig = params[2];
      {%- endif -%}
    } else {
      [{% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %}options{%- if Framework.IsAxios %}, axiosConfig{% endif %}] = params;
    }
  }
{% else %}
  options = params[0] as any;
  {%- if Framework.IsAxios -%}
  axiosConfig = params[1] as any;
  {%- endif -%}
{%- endif -%}

  const metaContext = useContext(QueryMetaContext);
  options = addMetaToOptions(options, metaContext);

  return useQuery<{{ ResultType }}, TError, TSelectData>({
    {%- comment -%} We add __ to the function name to avoid name clashing with parameters of this function {%- endcomment -%}
    {%- if Framework.IsAxios -%}
    queryFn: axiosConfig ? (context) => __{{ operation.ActualOperationName }}(context, axiosConfig) : __{{ operation.ActualOperationName }},
    {%- else -%}
    queryFn: __{{ operation.ActualOperationName }},
    {%- endif -%}
    queryKey: {{ operation.ActualOperationName }}QueryKey({% for parameter in operation.Parameters %}{{ parameter.VariableName }}{% unless forloop.last %}, {% endunless -%}{% endfor %}),
    ...{{ operation.ActualOperationName }}DefaultOptions as unknown as Omit<UseQueryOptions<{{ ResultType }}, TError, TSelectData>, 'queryKey'>,
    ...options,
  });
}
{% template Client.Method.Documentation %}
export function {{ operation.MethodAccessModifier }}set{{ operation.ActualOperationName | capitalize }}Data(queryClient: QueryClient, updater: (data: {{ ResultType }} | undefined) => {{ ResultType }}, {% for parameter in operation.Parameters -%}{%- assign ParameterType = parameter.Type | prepend: 'Types.' -%}{{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %}?{% endif %}: {{ ParameterType }}{{ parameter.TypePostfix }}{% unless forloop.last %}, {% endunless -%}{% endfor %}) {
  queryClient.setQueryData({{ operation.ActualOperationName }}QueryKey({% for parameter in operation.Parameters %}{{ parameter.VariableName }}{% unless forloop.last %}, {% endunless -%}{% endfor %}),
    updater
  );
}

{% template Client.Method.Documentation %}
export function {{ operation.MethodAccessModifier }}set{{ operation.ActualOperationName | capitalize }}DataByQueryId(queryClient: QueryClient, queryKey: QueryKey, updater: (data: {{ ResultType }} | undefined) => {{ ResultType }}) {
  queryClient.setQueryData(queryKey, updater);
}
  {% endif -%}
  {% endfor -%}

{% endif -%}
