{{
    const spec = require('./.spec.json');
    const dotUtils = require('./dotUtils.js');
}}{{= dotUtils.preamble() }}

// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version {{= spec.info.version }}

//! Automatically generated endpoint handles and data transfer structs.

mod dto;
pub use dto::*;

use std::future::Future;
use std::vec::Vec;

use url::form_urlencoded::Serializer;

use crate::Result;
use crate::consts::Region;
use crate::riot_api::RiotApi;

{{
    const endpointGroups = {};
    for (let path of Object.entries(spec.paths)) {
        let ep = path[1]['x-endpoint'];
        endpointGroups[ep] = endpointGroups[ep] || [];
        endpointGroups[ep].push(path);
    }
}}
impl RiotApi {
{{
    for (const endpointName of Object.keys(endpointGroups)) {
        const method = dotUtils.changeCase.snakeCase(endpointName);
        const type = dotUtils.changeCase.pascalCase(endpointName);
}}
    /// Handle for {{= type }} endpoints. This method is automatically generated.
    /// # Official API Reference
    /// <a href="https://developer.riotgames.com/api-methods/#{{= endpointName }}">https://developer.riotgames.com/api-methods/#{{= endpointName }}</a>
    #[inline]
    pub fn {{= method }}(&self) -> {{= type }} {
        {{= type }} { base: self }
    }
{{
    }
}}
}
{{
    for (let [ endpointName, endpointMethods ] of Object.entries(endpointGroups)) {
        let endpoint = dotUtils.changeCase.pascalCase(endpointName);
}}

/// {{= endpoint }} endpoints. This struct is automatically generated.
/// # Official API Reference
/// <a href="https://developer.riotgames.com/api-methods/#{{= endpointName }}">https://developer.riotgames.com/api-methods/#{{= endpointName }}</a>
pub struct {{= endpoint }}<'a> {
    base: &'a RiotApi,
}
impl<'a> {{= endpoint }}<'a> {
{{
        for (let [ route, path ] of endpointMethods)
        {
            let get = path.get;
            if (!get)
                continue;
            let operationId = get.operationId;
            let method = dotUtils.changeCase.snakeCase(operationId.slice(operationId.indexOf('.') + 1));

            let jsonInfo = get.responses['200'].content['application/json'];
            let returnType = dotUtils.stringifyType(jsonInfo.schema, endpoint, false, false);

            /* Cases if not rate limited. */
            let rateLimitExcluded = get['x-app-rate-limit-excluded'] ? true : false;

            /* Description processing. */
            let desc = get.description;
            let descArr = desc
                .replace(/(#+)\s*([^\\]+)\\n(.*?)([\\n$])/g,
                    (m, g1, g2, g3, g4) => `<h${g1.length}>${g2}</h${g1.length}>\\n${g3}${g4}`)
                .split('\n');

            /* Build argument comment & string. */
            let argBuilder = [];
            let makeParamCode = '';
            let allParams = get.parameters;
            let queryParams = [];
            let routeArgument = dotUtils.formatRouteArgument(route);
            if (allParams && allParams.length)
            {
                let pathParams = allParams.filter(p => 'path' === p.in)
                    .sort(p => route.indexOf(p.name));
                let reqParams = allParams.filter(p => 'path' !== p.in && p.required);
                let optParams = allParams.filter(p => 'path' !== p.in && !p.required)
                    .sort(p => {
                        let match = /(^[a-z]+|[A-Z]+(?![a-z])|[A-Z][a-z]+)/.exec(p.name);
                        return match.slice(1).reverse().join('');
                    });
                queryParams = reqParams.concat(optParams);

                for (let paramList of [ pathParams, reqParams, optParams ])
                {
                    let required = paramList === pathParams;
                    for (let param of paramList)
                    {
                        argBuilder.push(', ', dotUtils.changeCase.snakeCase(param.name), ': ',
                            dotUtils.stringifyType(param.schema, endpoint, !required, true, false));
                    }
                }

                routeArgument = dotUtils.formatRouteArgument(route, pathParams);
            }
            for (var descLine of descArr)
            {
}}
        ///{{= descLine ? ' ' + descLine : '' }}
{{
            }
}}
        /// # {{= get.externalDocs.description }}
        /// <a href="{{= get.externalDocs.url }}">{{= get.externalDocs.url }}</a>
        /// # Parameters
        /// * `region` - Region to query.
{{
            if (allParams)
            {
                for (let param of allParams)
                {
}}
        /// * `{{= param.name }}`{{= param.required ? '' : ' (optional)' }}{{= param.description ? ' - ' + param.description : ''}}
{{
                }
            }
}}
        pub fn {{= method }}(&self, region: Region{{= argBuilder.join('') }})
            -> impl Future<Output = Result<Option<{{= returnType }}>>> + 'a
        {
{{? queryParams.length }}
            let mut query_params = Serializer::new(String::new());
{{
            for (let queryParam of queryParams)
            {
}}
            {{= dotUtils.formatAddQueryParam(queryParam) }};
{{
            }
}}
            let query_string = query_params.finish();
{{?}}
            let path_string = {{= routeArgument }};
            self.base.get::<{{= returnType }}>("{{= operationId }}", region, path_string, {{= queryParams.length ? 'Some(query_string)' : 'None' }})
        }

{{
        }
}}
}
{{
    }
}}