import Source;

extends Source;

model Config {
  protocol: string(maxLength= 50, pattern= 'pattern'),
  importConfig: Source.Config,
  query: string,
  complexList: [[string]],
  floatNum: float, 
  longNum: long
}
type @protocol = string
type @pathname = string
type @endpointMap = map[string]string
type @source = Source
type @boolVirtual = boolean;
type @configs = [ Source.Config ];

init(config: Source.Config, secondParam: string){
  super(config, secondParam);
  @protocol = config.protocol;
  @pathname = secondParam;
  @boolVirtual = true;
  @configs[0] = config;
}

model ComplexRequest = {
  accessKey: string(name='accessKey'),
  body: readable(name='Body', example='Body', description='Body'),
  strs: [ string ](name='Strs', example='Strs', description='Strs'),
  header: {
    content: string(name='Content', example='The name of the region.', signed='true', description='The ID of the security group to which you want to assign the instance. Instances in the same security group can communicate with each other. The maximum number of instances that a security group can contain depends on the type of the security group. For more information, see the "Security group limits" section in [Limits](https://help.aliyun.com/document_detail/25412.html#SecurityGroupQuota).

>Notice:  The network type of the new instance must be the same as that of the security group specified by the `SecurityGroupId` parameter. For example, if the specified security group is of the VPC type, the new instance is also of the VPC type and you must specify `VSwitchId`.

If you do not use `LaunchTemplateId` or `LaunchTemplateName` to specify a launch template, you must specify SecurityGroupId. Take note of the following items:

*   You can set `SecurityGroupId` to specify a single security group or set `SecurityGroupIds.N` to specify one or more security groups. However, you cannot specify both `SecurityGroupId` and `SecurityGroupIds.N`.
*   If `NetworkInterface.N.InstanceType` is set to `Primary`, you cannot specify `SecurityGroupId` or `SecurityGroupIds.N` but can specify `NetworkInterface.N.SecurityGroupId` or `NetworkInterface.N.SecurityGroupIds.N`.', nullable=true, checkBlank=true, sensitive=true),
    listSub: [{
      listSubItem: string(name='listSubItemName'),
      listSubItemSub: Config(name='listSubItemSubName')
    }],
    listStr: [string](name='listStr'),
    sourceClient: Source(name='sourceClient'),
    sourceConfig: Source.Config(name='sourceConfig'),
    subModel: {
      subModelStr: string
    }(name='subModel'),
    subArray: [
      Config
    ](name='subArray'),
    subMutiArray: [[
      Config
    ]](name='subMutiArray'),
  }(description='header', name='header'),
  num: number(name='num'),
  client: Source(name='client'),
  part?: [
    {
      partNumber?: string(description='PartNumber', name='PartNumber')
    }
  ](description='Part', name='Part', deprecated=true),
  configs: {
    key: string(name='key'),
    value: [ string ](name='value'),
    extra: map[string] string(name='extra')
  }(name='configs'),
  dict: map[string]any(name='dict'),
  submodelMap: map[string]Source.Config(name='submodelMap'),
  array?: [[ 
    {
      type?: string(name='type'),
      link?: string(name='link'),
      text?: string(name='text'),
    }
  ]  ](name='array'),
  array1?: [[string]](name='array1'),
  array2?: [Config](name='array2'),
}

static function arrayAssign3(request: ComplexRequest, config: string): void {
  request.configs.value[0] = config;
  var i : integer = 0;
  request.configs.value[i] = config;
}

static function mapAccess(request: ComplexRequest): string {
   var configInfo = request.configs.extra['name'];
  return configInfo;
}

static function mapAccess2(request: Source.Request): string {
   var configInfo = request.configs.extra['name'];
  return configInfo;
}

static function mapAccess3(): string {
  var data = {
    mapAcc  = {
      map2 = {
        value = 'string'
      }
    } 
  };
  return data.mapAcc.map2['value'];
}

static function mapAssign(request: ComplexRequest, name: string): void {
  request.configs.extra['name'] = name;
  var data = {};
  data.header = null;
  request.dict = {
    test = "demo",
  };
}

static function arrayAssign2(config: string): [ string ] {
  var data = {
    configs = ['a', 'b', 'c']
  };
  data.configs[3] = config;
  var i : integer = 3;
  data.configs[i] = config;
  return data.configs;
}

static function arrayAssign(config: string): [ string ] {
  var configs = ['a', 'b', 'c'];
  configs[3] = config;
  var i : integer = 3;
  configs[i] = config;
  var i32 : int32 = 3;
  configs[i32] = config;
  var i64 : int64 = 3;
  configs[i64] = config;
  var num : number = 3;
  configs[num] = config;
  return configs;
}

static function arrayAccess3(request: ComplexRequest): string {
  var configVal = request.configs.value[0];
  var i : integer = 0;
  configVal = request.configs.value[i];
  return configVal;
}

static function arrayAccess2(): string {
  var data = {
    configs = ['a', 'b', 'c']
  };
  var config = data.configs[0];
  var i : integer = 0;
  config = data.configs[i];
  return config;
}

static function arrayAccess(): string {
  var configs = ['a', 'b', 'c'];
  var config = configs[0];
  var i : integer = 0;
  config = configs[i];
  var i32 : int32 = 3;
  config = configs[i32];
  var i64 : int64 = 3;
  config = configs[i64];
  var num : number = 3;
  config = configs[num];
  return config;
}

async function hello(request: object, strs: [ string ]): [ string ] {
  return array1();
}

static async function print(reqeust: $Request, reqs: [ ComplexRequest ], response: $Response, val: map[string]string): Source.Request {
  return new Source.Request{};
}

api Complex1(request: ComplexRequest, client: Source): Source.RuntimeObject {
  var name = 'complex';
  var conf = new Config{ floatNum = 0.1 };
  conf.floatNum = 1.1;
  var mapVal = {
    test="ok"
    };
  __request.protocol = @endpointMap[@protocol];
  __request.port = request.num;
  __request.method = 'GET';
  __request.pathname = `/${@pathname}`;
  __request.query = {
    date = '2019',
  };
  var reqInstance = __request;
  var boolItem = !@boolVirtual;
} returns {
  if (true && true){
    return null;
  } else if(true || false){
    return new Source.RuntimeObject{};
  } else {
    return null;
  }
  client.print(request, '1');
  hello(request, ["1","2"]);
  hello(null, null);
  Complex3(null);
  return {};
} runtime {
  timeouted = 'retry'
} 

api Complex2(request: ComplexRequest, str: [ string ], val: map[string]string, complexList: [[[string]]]): object {
  var name = 'complex';
  var config = new Source.Config{};
  var client = new Source(config, 'testSecond');
  var subModel = new Source.Request.submodel{};
  var nestingList = [[[['test']]]];
  __request.protocol = 'HTTP';
  __request.port = 80;
  __request.method = 'GET';
  __request.pathname = '/';
  __request.query = {
    date = '2019',
    protocol = __request.protocol,
  };
  return {};
}

api Complex3(request: ComplexRequest): ComplexRequest {
  var name = 'complex';
  __request.protocol = templateString();
  __request.port = 80;
  __request.method = 'GET';
  __request.pathname = '/';
  __request.body = 'body';
  __request.query = {
    date = '2019',
  };
} returns {
  if(true){
    retry;
  }
  var resp = __response;
  var req = new Source.Request{
    accesskey = request.accessKey,
    region = resp.statusMessage
  };
  array0(request);
  req.accesskey = 'accesskey';
  req.accesskey = request.accessKey;
  printNull(Config);
  Source.array(request, '1');
  return {
    ...__request.query
  };
}

static async function printNull(cls: class): void {
  try {
    var str = templateString();
  } catch(e) {
    var errStr = e.message;
  } finally {
    var final = 'ok';
  }

  try {
    var strNoCatch = templateString();
  } finally {
    var finalNoCatch = 'ok';
  }
}

static function array0(req: object): [ any ] {
  var temp = new Source.Config{};
  var anyArr : [Source.Config] = [temp];
  return [];
}

static function array1(): [ string ] {
  return ["1"];
}

async function templateString(): string {
  return `${@protocol}`;
}

static function returnObj(params: string): object {
  params = "test";
  return {};
}
