import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
import { CertApplyPluginNames, CertInfo, CertReader } from "@certd/plugin-cert";
import { AliyunAccess, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";

@IsTaskPlugin({
  name: 'AliyunDeployCertToFC',
  title: '阿里云-部署至阿里云FC(3.0)',
  icon: 'svg:icon-aliyun',
  group: pluginGroups.aliyun.key,
  desc: '部署证书到阿里云函数计算（FC3.0）,【注意】证书的加密算法必须选择【pkcs1旧版】',
  needPlus: false,
  default: {
    strategy: {
      runStrategy: RunStrategy.SkipWhenSucceed,
    },
  },
})
export class AliyunDeployCertToFC extends AbstractTaskPlugin {
  @TaskInput({
    title: '域名证书',
    helper: '请选择证书申请任务输出的域名证书',
    component: {
      name: 'output-selector',
      from: [...CertApplyPluginNames],
    },
    required: true,
  })
  cert!: CertInfo;

  @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
  certDomains!: string[];

  @TaskInput({
    title: 'FC大区',
    value: 'cn-hangzhou',
    component: {
      name: 'a-auto-complete',
      vModel: 'value',
      options: [
        { value: 'cn-qingdao', label: '华北1（青岛）' },
        { value: 'cn-beijing', label: '华北2（北京）' },
        { value: 'cn-zhangjiakou', label: '华北 3（张家口）' },
        { value: 'cn-huhehaote', label: '华北5（呼和浩特）' },
        { value: 'cn-hangzhou', label: '华东1（杭州）' },
        { value: 'cn-shanghai', label: '华东2（上海）' },
        { value: 'cn-shenzhen', label: '华南1（深圳）' },
        { value: 'ap-southeast-2', label: '澳大利亚（悉尼）' },
        { value: 'eu-central-1', label: '德国（法兰克福）' },
        { value: 'ap-southeast-3', label: '马来西亚（吉隆坡）' },
        { value: 'us-east-1', label: '美国（弗吉尼亚）' },
        { value: 'us-west-1', label: '美国（硅谷）' },
        { value: 'ap-northeast-1', label: '日本（东京）' },
        { value: 'ap-southeast-7', label: '泰国（曼谷）' },
        { value: 'cn-chengdu', label: '西南1（成都）' },
        { value: 'ap-southeast-1', label: '新加坡' },
        { value: 'ap-south-1', label: '印度（孟买）' },
        { value: 'ap-southeast-5', label: '印度尼西亚（雅加达）' },
        { value: 'eu-west-1', label: '英国（伦敦）' },
        { value: 'cn-hongkong', label: '中国香港' },
      ],
    },
    required: true,
  })
  regionId!: string;


  @TaskInput({
    title: '阿里云账号id',
    helper: '阿里云主账号ID，右上角头像下方获取',
    component: {
      name: 'a-input',
      vModel:"value"
    },
    required: true,
  })
  accountId!: string;

  @TaskInput({
    title: 'Access授权',
    helper: '阿里云授权AccessKeyId、AccessKeySecret',
    component: {
      name: 'access-selector',
      type: 'aliyun',
    },
    required: true,
  })
  accessId!: string;

  @TaskInput(
    createRemoteSelectInputDefine({
      title: 'FC域名',
      helper: "请选择要部署证书的域名\n【注意】证书的加密算法必须选择【pkcs1旧版】（否则会报'private key' has to be in PEM format错误）",
      typeName: 'AliyunDeployCertToFC',
      action: AliyunDeployCertToFC.prototype.onGetDomainList.name,
      watches: ['accessId', 'regionId'],
    })
  )
  fcDomains!: string[];

  @TaskInput({
    title: '域名支持的协议类型',
    component: {
      name: 'a-select',
      value: '',
      options: [
        { value: '', label: '保持原样（适用于原来已经开启了HTTPS）' },
        { value: 'HTTPS', label: '仅HTTPS' },
        { value: 'HTTP,HTTPS', label: 'HTTP与HTTPS同时支持' },
      ],
    },
  })
  protocol!: string;

  async onInstance() {}

  async execute(): Promise<void> {
    this.logger.info('开始部署证书到阿里云');
    const access = await this.getAccess<AliyunAccess>(this.accessId);

    const client = await this.getClient(access);

    const $Util = await import('@alicloud/tea-util');
    const $OpenApi = await import('@alicloud/openapi-client');
    for (const domainName of this.fcDomains) {
      const params = new $OpenApi.Params({
        // 接口名称
        action: 'UpdateCustomDomain',
        // 接口版本
        version: '2023-03-30',
        // 接口协议
        protocol: 'HTTPS',
        // 接口 HTTP 方法
        method: 'PUT',
        authType: 'AK',
        style: 'FC',
        // 接口 PATH
        pathname: `/2023-03-30/custom-domains/${domainName}`,
        // 接口请求体内容格式
        reqBodyType: 'json',
        // 接口响应体内容格式
        bodyType: 'json',
      });
      // body params
      const certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt))

      const body: { [key: string]: any } = {
        certConfig: {
          certName: certName,
          certificate: this.cert.crt,
          privateKey: this.cert.key,
        },
      };
      if (this.protocol) {
        body.protocol = this.protocol;
      }

      const runtime = new $Util.RuntimeOptions({});
      const request = new $OpenApi.OpenApiRequest({ body });
      // 复制代码运行请自行打印 API 的返回值
      // 返回值实际为 Map 类型，可从 Map 中获得三类数据：响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。
      await client.callApi(params, request, runtime);
      this.logger.info(`部署[${domainName}]成功`);
    }
  }

  async getClient(access: AliyunAccess) {
    const $OpenApi = await import('@alicloud/openapi-client');
    const config = new $OpenApi.Config({
      accessKeyId: access.accessKeyId,
      accessKeySecret: access.accessKeySecret,
    });
    // Endpoint 请参考 https://api.aliyun.com/product/FC
    config.endpoint = `${this.accountId}.${this.regionId}.fc.aliyuncs.com`;
    return new $OpenApi.default.default(config);
  }

  async onGetDomainList(data: any) {
    if (!this.accessId) {
      throw new Error('请选择Access授权');
    }
    const access = await this.getAccess<AliyunAccess>(this.accessId);
    const client = await this.getClient(access);

    const $OpenApi = await import('@alicloud/openapi-client');
    const $Util = await import('@alicloud/tea-util');
    const params = new $OpenApi.Params({
      // 接口名称
      action: 'ListCustomDomains',
      // 接口版本
      version: '2023-03-30',
      // 接口协议
      protocol: 'HTTPS',
      // 接口 HTTP 方法
      method: 'GET',
      authType: 'AK',
      style: 'FC',
      // 接口 PATH
      pathname: `/2023-03-30/custom-domains`,
      // 接口请求体内容格式
      reqBodyType: 'json',
      // 接口响应体内容格式
      bodyType: 'json',
    });

    const runtime = new $Util.RuntimeOptions({});
    const request = new $OpenApi.OpenApiRequest({});
    // 复制代码运行请自行打印 API 的返回值
    // 返回值实际为 Map 类型，可从 Map 中获得三类数据：响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。
    const res = await client.callApi(params, request, runtime);

    const list = res?.body?.customDomains;
    if (!list || list.length === 0) {
      throw new Error('没有找到FC域名，请先创建FC域名');
    }

    const options = list.map((item: any) => {
      return {
        label: item.domainName,
        value: item.domainName,
        title: item.domainName,
        domain: item.domainName,
      };
    });
    return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
  }
}

new AliyunDeployCertToFC();
