import EventEmitter from 'events';
// eslint-disable-next-line import/no-extraneous-dependencies
import { Command } from 'commander';
declare module 'minidev' {

  export type DeepPartial<T> = {
    [P in keyof T]?:T[P] extends Record<any, any> ? DeepPartial<T[P]> : T[P];
  };


  export interface IConfigInits {
    defaults: {
      [key: string]: any
    };
    globalConfigFilePath: string;
    projectConfigRelativePath: string;
  }

  export interface IMinidevLibDefaults {

    name: string;

    description: string;

    config: IConfigInits;
  }

  /**
   * 配置默认项
   * @param overrides
   */
  export function useDefaults(overrides: DeepPartial<IMinidevLibDefaults>): void;

  export function usePlugin(plugin: IMinidevPlugin): void;

  export function setSilent(boolean): void;

  export function setSpinnerEnabled(enabled: boolean): void;

  export function setLogLevelVerboseEnabled(enabled: boolean): void;

  export type MaybePromise<T = void> = T | Promise<T>;

  export interface IMinidevPlugin {

    name: string,

    contribute(registry: IMinidevPluginRegistry, injector: { get: (token: any) => any}): void;

  }

  export interface IMinidevPluginRegistry {
    hooks: {
      onCreateDevServer(hook: (context: {
        devServer: IDevServer;
      }) => void, weight?: number | undefined);
      onDidRunLocalBuild(hook: (context: {
        build: ILocalBuildCompileBuild;
      }) => void, weight?: number | undefined);
    }
  }

  export interface IAuthPathOptions {
    identityKeyPath?: string;
  }

  export interface IVersionListResult {
    /**
     * 端参数，用于查询多端版本，不传默认为支付宝端。 高德端：com.amap.app
     */
    bundleId?: string;

    appVersion: string;

    versionDescription: string;

    versionStatus: string;

    createTime: string;

    operateName: string;

    canRelease: any;
  }


  export const minidev: IMinidev;

  export default minidev;

  export function getProgram(): Command;

  export interface IMinidev {

    /**
     * 构建编译小程序
     * @param opts
     */
    build(opts: IBuildArgs): Promise<ILocalBuildCompileBuild>;


    /**
     * 启动开发服务器 DevServer
     * @param opts
     * @param onDone
     */
    dev(opts: IDevCommandArgs, onDone?: () => any): Promise<IDevServerCompileBuild>

    /**
     * 使用 DevServer 产物发起真机预览 （此模式仅整包, 无法验证分包可用性）
     * 需要在运行 dev 之后运行
     * @param opts
     */
    devPreview(opts: IDevPreviewArgs, build?: IDevServerCompileBuild): Promise<IGenerateDebugQRCodeResult>;


    devWebSimulator(opts:IDevWebSimulatorArgs, build?: IDevServerCompileBuild): Promise<IWebSimulatorLauncher>


    /**
     * 使用 DevServer 产物发起真机调试 （此模式仅整包, 无法验证分包可用性）
     * 需要在运行 dev 之后运行
     * @param opts
     */
    devRemoteDebug(opts: IDevRemoteDebugArgs, build?: IDevServerCompileBuild): Promise<IRemoteDebugReturn>


    /**
     * 启动小程序开发者工具模拟器对 DevServer 产物进行调试
     * 需要在运行 dev 之后运行
     * @param opts
     */
    startIdeForDevServer(opts: IDevIDEOptions, build?: IDevServerCompileBuild): Promise<void>;

    /**
     * 进行工具授权
     * @param opts
     */
    login(opts: IClientTypeOptions, onCreateLoginTask?: (loginTask: ILoginTask) => void): Promise<void>;

    /**
     * 上传发布小程序
     * @param opts
     * @param @optional hooks
     */
    upload(opts: IUploadOptions, hooks?: IPublishHooks): Promise<IPublishResult>;


    /**
     * 构建并发起真机预览
     * @param opts
     */
    preview(opts: IPreviewArgs): Promise<IGenerateDebugQRCodeResult>;

    /**
     * 构建并发起远程调试
     * @param opts
     */
    remoteDebug(opts: IRemoteDebugArgs): Promise<IRemoteDebugReturn>

    /**
     * 清除构建缓存
     */
    cleanBuildCache(): Promise<void>;

    /**
     * 打包源码
     * @param opts
     */
    pack(opts: IPackSourceOptions): Promise<void>;

    /**
     * 启动 IDE
     * @param opts
     */
    startIde(opts: IIDECommandOptions): Promise<void>;

    /**
     * 设置相关操作
     */
    config: IMinidevConfig;


    /**
     * 小程序管理相关操作
     */
    app: IMinidevApp

  }

  export interface ILoginTask {

    on(event: 'qrcode-generated', listener: (qrCodeUrl: string) => any): any;

    on(event: 'success', listener: () => any): any;

    on(event: 'scan', listener: () => any): any;

    on(event: 'polling', listener: (remainingMs: number) => any): any;

    removeListener(event: string, listener: (...args) => any): any;

  }

  export interface IRemoteDebugReturn extends IGenerateDebugQRCodeResult{
    /**
     * 调试地址
     */
    debugUrl: string;
    /**
     * 停止调试服务
     */
    stopServer: () => Promise<void>;

  }

  export interface IPublishHooks {

    onLog?:(data: string) => void;

    onTaskCreated?: (taskId: string) => void;

    onVersionCreated?: (version: string) => void;
  }

  export interface IMinidevConfig {

    get<T = any>(configName: string, opts?: IConfigOptions): Promise<T>;

    set<T = any>(configName: string, value: T, opts?: IConfigOptions): Promise<void>;

    /**
     * 设置 **RUNTIME** 的配置项
     */
    useRuntime(config: Record<string, any>): Promise<void>;

  }

  export interface IAppInfo {

    appId: string;

    appName: string;

    logoUrl: string;

    subApplicationType: 'TINYAPP_NORMAL' | 'TINYAPP_PLUGIN' | 'TINYAPP_TEMPLATE'
  }

  export interface IGetAppUploadedVersionArgs extends IAppIdArgs, IClientTypeOptions, IAuthPathOptions {

  }

  export interface IVersionListOptions extends IAppIdArgs, IClientTypeOptions, IAuthPathOptions {

    /**
     * 版本状态列表
     */
    versionStatus?: string;

    /**
     * 以 JSON 格式打印
     */
    json?: boolean;
  }

  export interface IMinidevApp {

    /**
     * 获取小程序列表
     * @param options
     */
    getList(options: IClientTypeOptions): Promise<IAppInfo>;

    /**
     * 获取小程序的最新上传版本号
     * @param options
     */
    getUploadedVersion(options: IGetAppUploadedVersionArgs): Promise<string>;


    /**
     * 获取小程序的上传版本列表
     * @param options
     */
    getUploadedVersionList(options: IVersionListOptions): Promise<IVersionListResult>;

    /**
     * 删除指定版本
     * 如果该版本为体验版，会先取消该体验版
     * @param options
     */
    deleteVersion(options: IAppIdAndVersionOptions): Promise<void>;

    /**
     * 取消体验版
     * @param options
     */
    cancelExperience(options: IAppIdAndVersionOptions): Promise<void>;

    /**
     * 设置体验版
     * @param options
     * @return qrCodeUrl 体验版二维码
     */
    setExperience(options: IAppIdAndVersionOptions): Promise<{qrCodeUrl: string}>;


  }

  export interface IAppIdAndVersionOptions extends IAppIdArgs, IClientTypeOptions, IAuthPathOptions {
    version: string;
  }

  export interface IWebSimulatorLauncher {

    bundled: string;

    /**
     * 这里返回的 simulator 和 devtool 均为不含 uuid 的模板地址
     * 如何使用:
     *  const simulatorUrl = separated.simulator.replace('___uuid___', '当前会话的 uuid')
     *  const devtoolUrl = separated.devtool.replace('___uuid___', '当前会话的 uuid')
     */
    separated: {
      simulator: string;
      devtool: string;
    }
  }

  export interface IConfigOptions extends IProjectArgs {

    scope?: ConfigScope.GLOBAL | ConfigScope.PROJECT;

  }

  export enum ConfigScope {

    /**
     * 用户配置
     */
    GLOBAL = 'global',

    /**
     * 当前项目的配置
     */
    PROJECT = 'project',

  }

  export interface IDevPreviewArgs extends IGenerateQrCodeArgs, IAppIdArgs, IAuthPathOptions {

  }

  export interface IDevWebSimulatorArgs extends IOptionalAppIdArgs, IClientTypeOptions, ICompileModeOptions {

    /**
     * 自动打开模拟器, 默认行为为打开
     */
    autoOpen?: boolean;

    lyraParams?: ILyraParams;

  }

  export interface ILyraParams {
    rendererExtend?: string[];
  }

  export interface IGenerateQrCodeArgs extends IClientTypeOptions, ICompileModeOptions, IAMPEOptions {

    /**
   * @deprecated 同 ignoreHttpDomainCheck
   */
    ignoreHttpReqPermission?: boolean;

    /**
     * 忽略 http 请求白名单校验
     */
    ignoreHttpDomainCheck?: boolean;

    /**
     * 忽略 webview 加载域名白名单校验
     */
    ignoreWebViewDomainCheck?: boolean;

    /**
     * 是否自动推送到客户端
     */
    autoPush?: boolean;

     /**
      * 自定义启动参数
    */
    launchParams?: any;

  }

  export interface ICompileModeOptions {

    /**
     * 入口页面
     */
     page?: string;

     /**
      * 页面参数, 可在当前页面的 onLoad 中取得，如: name=vendor&color=black
      */
     pageQuery?: string;

     /**
      * 全局参数，app.js 的 onLaunch 中取得，如: name=vendor&color=black
      */
     query?: string;

     /**
      * 场景值
      */
     scene?: string;

     /**
      * 模拟更新
      */
     simulateUpdate?: boolean;

  }

  export interface IAMPEOptions {

    /**
     * 移动应用 ID
     */
    ampeProductId?: string;

    /**
     * 设备 ID
     */
    ampeDeviceId?: string;

    /**
     * 产品 ID
     */
    ampeHostAppId?: string;

  }

  export interface IClientTypeOptions {

    /**
     * 端类型
     */
    clientType?: string;

    /**
    * <高级> 开放平台 bundleId, 此项会覆盖 clientType 的效果
    */
    bundleId?: string;

  }


  export interface IDevCommandArgs extends IBuildArgs {


    /**
     * 是否开启 HMR
     */
    hmr?: boolean;

    /**
     * 是否启用 https
     */
    // https?: boolean;

    /**
     * 指定 Host，默认 Host 为 127.0.0.1
     */
    host?: string,

    /**
     * devServer 的端口号
     */
    port?: number,


    /**
     * log 名，api 调用时使用
     */
    logName?: string;

  }


  export interface IBuildArgs extends IProjectArgs, IOptionalAppIdArgs {
    /**
     * 指定构建缓存路径, 默认为系统缓存路径
     */
    cacheDir?: string;

    /**
     * 产物路径
     */
    output?: string;

    /**
     * 是否开启 sourceMap
     */
    sourceMap?: boolean;

    /**
     * 插件 Id，构建插件时将生成到代码中
     */
    pluginId?: string;

    /**
     * 多进程编译
     */
    parallel?: boolean;

    /**
     * 是否需要压缩，默认不开
     */
    minify?: boolean;

    /**
     * 构建类型
     */
    buildTarget?: EBuildTarget;

    /**
     * 是否开启 less 编译
     */
    enableLess?: boolean;

    /**
     * 是否开启 ts 编译
     */
    enableTypescript?: boolean;

    /**
     * 是否开启紧凑产物模式
     */
    compact?: boolean;

  }

  export interface IProjectArgs {

    /**
     * 项目路径， 默认 cwd
     */
    project?: string;

  }

  export interface IOptionalAppIdArgs {

    /**
     * 小程序应用 id
     */
    appId?: string;

  }

  export interface IDevServerCompileBuild {

    devServer: IDevServer;

    project: string;

    dist: string;

  }

  export interface IAppIdArgs extends IOptionalAppIdArgs {

    /**
     * 小程序应用 id
     */
    appId: string;

  }

  export interface IDevServer extends EventEmitter {

    readonly id: string;

    /**
     * 服务地址
     */
    readonly server: string;

    readonly host: string

    readonly port: number;

    /**
     * devServer 的产物路径
     */
    dist: string;

    /**
     * devServer 启动
     * @param event
     * @param listener
     */
    on(event: 'start', listener: () => any): this;

    /**
     * 开始编译
     * @param event
     * @param listener
     */
    on(event: 'compile', listener: () => any): this;

    /**
     * 编译成功完成
     * @param event
     * @param listener
     */
    on(event: 'done', listener: (result: IDevDone) => any): this;

    /**
     * 编译出错
     * @param event
     * @param listener
     */
    on(event: 'error', listener: (error: IDevError) => any): this;

    /**
     * devServer 进程被关闭
     * @param event
     * @param listener
     */
    on(event: 'exit', listener: (code?: number) => any): this;

    /**
     * 开启 hmr 时，当 hmr 完成会发送这个事件
     * @param event
     * @param listener
     */
    on(event: 'hmr-done', listener: () => any): this;

    /**
     * 开启 hmr 时，当 hmr 出错时会发送这个事件
     * @param event
     * @param listener
     */
    on(event: 'hmr-error', listener: (error: IDevError) => any): this;

    /**
    * 发生在 mini.project.json 文件被变更的时候， 这种时机一般期望重新启动 devServer
    * @param event
    */
    on(event: 'project-config-change', listener: () => any): this;

    /**
    * devServer 输出日志
    * @param event
    */
    on(event: 'log', listener: (data: string) => any): this;



    once(event: 'start', listener: () => any): this;
    once(event: 'compile', listener: () => any): this;
    once(event: 'done', listener: (result: IDevDone) => any): this;
    once(event: 'error', listener: (error: IDevError) => any): this;
    once(event: 'exit', listener: (code?: number) => any): this;
    once(event: 'hmr-done', listener: () => any): this;
    once(event: 'hmr-error', listener: (error: IDevError) => any): this;
    once(event: 'project-config-change', listener: () => any): this;
    once(event: 'log', listener: (data: string) => any): this;

    restart(options?: {appId?: string}): Promise<void>;

    stop(): Promise<void>;

  }

  export enum EBuildTarget {
    Preview = 'Preview',
    RemoteLegacy = 'RemoteLegacy',
    RemoteX = 'RemoteX',
    RemoteXLite = 'RemoteXLite',
    RemoteBoatman = 'RemoteBoatman',
    Publish = 'Publish'
  }

  export interface IDevError {
    message: string;
    stack?: any;
  }

  export interface IDevDone {
    success: boolean;
  }


  export interface IDevIDEOptions extends IOptionalAppIdArgs, IIDECommandOptions {

  }

  export interface IGenerateDebugQRCodeResult {

    /**
     * 二维码
     */
    qrcodeUrl: string;
    /**
     *
     */
    qrcodeSchema?: string;

    /**
     * 生成的版本号
     */
    version: string;
  }

  export interface IIDECommandOptions extends IProjectArgs {

    /**
     * lite 模式启动
     */
    lite?: boolean;

    /**
     * 项目类型
     */
    projectType?: string

    /**
     * IDE 安装路径
     */
    appPath?: string;
  }

  export interface IDevRemoteDebugArgs extends IGenerateQrCodeArgs, IAppIdArgs, IAuthPathOptions {

    /**
     * 是否自动打开 devtool，cli 模式默认自动打开， jsApi 调用默认不打开
     */
    autoOpenDevtool?: boolean;

  }

  export interface IPublishResult {

    version: string;

    /**
     * 如果设置为体验版，则添加这个字段，为体验包二维码
     */
    experienceQrCodeUrl?: string;

  }

  export interface IUploadOptions extends IAppIdArgs, IClientTypeOptions, IProjectArgs, IAuthPathOptions {

    /**
     * 上传的版本号，如果不传入，会尝试从后台拉取版本后自动添加一位 patch 号 (例: 1.1.1 => 1.1.2)
     * 参考语义化版本:
     * [major].[minor].[patch]
     */
    version?: string;


    /**
    * 上传成功后，自动设置为体验版本 (需要对应权限)
    */
    experience?: boolean;

    /**
     * 上传时删除指定版本号
     */
    deleteVersion?: string;

    /**
     * 是否小游戏
     */
    isGame?: boolean;

    /**
     * 版本描述，用于在开放平台显示
     */
    versionDescription?: string;
  }

  export interface IPreviewArgs extends IBuildArgs, IGenerateQrCodeArgs, IAuthPathOptions {

    /**
     * 小程序应用 id
     */
    appId: string;

  }

  export interface ILocalBuildCompileBuild {

    result: TBuildPackResult

    project: string;

    dist: string;

    buildTarget: EBuildTarget;

  }

  export type TBuildPackResult = INormalBuildPackResult | ISubPackBuildPackResult | IPluginBuildPackResult;

  export interface IPluginBuildPackResult {
      compileType: ECompileType.Plugin;
      enableSubPack: false;
      client: Omit<INormalBuildPackResult, 'compileType' | 'enableSubPack' | 'extendInfo'>;
      plugin: Omit<INormalBuildPackResult, 'compileType' | 'enableSubPack' | 'extendInfo'>;
      components?: string[];
      /**
       * 额外的启动参数
       */
      extraLaunchParams?: Record<string, unknown>;
  }

  export enum ECompileType {
    MiniProgram = 'mini',
    Plugin = 'plugin'
  }

  export interface INormalBuildPackResult {
      compileType: ECompileType.MiniProgram;
      enableSubPack: false;
      tarFilePath: string;
      size: number;
      outPath?: string;
      components?: string[];
      gzipFilePath?: string;
      sourceMapZipFile?: string;
      /**
       * 额外的启动参数
       */
      extraLaunchParams?: Record<string, unknown>;
      webpackStatPath?: string;
      statPath?: string;
  }

  export interface ISubPackBuildPackResult {
      compileType: ECompileType.MiniProgram;
      enableSubPack: true;
      tarFilePath: string;
      size: number;
      subPackages: ISubPackageResult[];
      outPath?: string;
      components?: string[];
      gzipFilePath?: string;
      sourceMapZipFile?: string;
      subPackSourceMapZipFile?: string;
      /**
       * 额外的启动参数
       */
      extraLaunchParams?: Record<string, unknown>;
      webpackStatPath?: string;
      statPath?: string;
      webpackChunkStatPath?: string;
      chunkStatPath?: string;
  }

  export interface ISubPackageResult {
      type: 'MAIN' | 'SUB';
      path: string;
      size: number;
      tarFilePath: string;
      gzipFilePath?: string;
      statPath?: string;
      webpackStatPath?: string;
  }

  export interface IRemoteDebugArgs extends IBuildArgs, IGenerateQrCodeArgs, IAuthPathOptions {

    /**
     * 小程序应用 id
     */
    appId: string;

    /**
     * 是否自动打开 devtool，cli 模式默认自动打开， jsApi 调用默认不打开
     */
    autoOpenDevtool?: boolean;

  }

  export interface IPackSourceOptions extends IProjectArgs {

    /**
     * 输出文件夹
     */
    dir?: string;

    /**
     * 输出文件名
     */
    filename?: string;

  }

}
