#![allow(missing_docs, unused_variables, trivial_casts)]

{{#hasCallbacks}}
mod server;
{{/hasCallbacks}}

#[allow(unused_imports)]
use futures::{future, Stream, stream};
#[allow(unused_imports)]
use {{{externCrateName}}}::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, models,
{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
                      {{{operationId}}}Response,
      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
                     };
use clap::{App, Arg};

// NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels.
//     See https://docs.rs/env_logger/latest/env_logger/  for more details

#[allow(unused_imports)]
use log::info;

// swagger::Has may be unused if there are no examples
#[allow(unused_imports)]
use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString};

type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString);

mod client_auth;
use client_auth::build_token;


// rt may be unused if there are no examples
#[allow(unused_mut)]
fn main() {
    env_logger::init();

    let matches = App::new("client")
        .arg(Arg::with_name("operation")
            .help("Sets the operation to run")
            .possible_values(&[
{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
        {{#vendorExtensions}}
          {{^x-no-client-example}}
                "{{{operationId}}}", 
          {{/x-no-client-example}}
        {{/vendorExtensions}}
      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
            ])
            .required(true)
            .index(1))
        .arg(Arg::with_name("https")
            .long("https")
            .help("Whether to use HTTPS or not"))
        .arg(Arg::with_name("host")
            .long("host")
            .takes_value(true)
            .default_value("{{{serverHost}}}")
            .help("Hostname to contact"))
        .arg(Arg::with_name("port")
            .long("port")
            .takes_value(true)
            .default_value("{{{serverPort}}}")
            .help("Port to contact"))
        .get_matches();

    // Create Bearer-token with a fixed key (secret) for test purposes.
    // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server
    // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side.
    // See https://github.com/Keats/jsonwebtoken for more information

    let auth_token = build_token(
            Claims {
                sub: "tester@acme.com".to_owned(), 
                company: "ACME".to_owned(),
                iss: "my_identity_provider".to_owned(),
                // added a very long expiry time
                aud: "org.acme.Resource_Server".to_string(),
                exp: 10000000000,
                // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization.
                scopes: [
                  {{#authMethods}}
                   {{#scopes}}
                            "{{{scope}}}",
                   {{/scopes}}
                  {{/authMethods}}
                ].join(", ")
            }, 
            b"secret").unwrap();

    let auth_data = if !auth_token.is_empty() {
        Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token}))
    } else {
        // No Bearer-token available, so return None
        None
    };

    let is_https = matches.is_present("https");
    let base_url = format!("{}://{}:{}",
        if is_https { "https" } else { "http" },
        matches.value_of("host").unwrap(),
        matches.value_of("port").unwrap());

    let context: ClientContext =
        swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default());

    let mut client : Box<dyn ApiNoContext<ClientContext>> = if matches.is_present("https") {
        // Using Simple HTTPS
        let client = Box::new(Client::try_new_https(&base_url)
            .expect("Failed to create HTTPS client"));
        Box::new(client.with_context(context))
    } else {
        // Using HTTP
        let client = Box::new(Client::try_new_http(
            &base_url)
            .expect("Failed to create HTTP client"));
        Box::new(client.with_context(context))
    };

    let mut rt = tokio::runtime::Runtime::new().unwrap();
{{#hasCallbacks}}

    // We could do HTTPS here, but for simplicity we don't
    rt.spawn(server::create("127.0.0.1:8081", false));
{{/hasCallbacks}}

    match matches.value_of("operation") {
{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
        {{#vendorExtensions}}
          {{#x-no-client-example}}
        /* Disabled because there's no example.
          {{/x-no-client-example}}
        {{/vendorExtensions}}
        Some("{{{operationId}}}") => {
            let result = rt.block_on(client.{{{vendorExtensions.x-operation-id}}}(
                {{#allParams}}
                  {{{vendorExtensions.x-example}}}{{^-last}},{{/-last}}
                {{/allParams}}
            ));
            info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has<XSpanIdString>).get().clone());
        },
        {{#vendorExtensions}}
          {{#x-no-client-example}}
        */
          {{/x-no-client-example}}
        {{/vendorExtensions}}
      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
        _ => {
            panic!("Invalid operation provided")
        }
    }
}
