
import { Report } from "./report.uts";
import { StatType } from "./stat-type";
import { EventParams, UniStatOptions, ErrorCallback, ReportErrorCode } from '../../interface.uts'
import { is_page, is_page_report, get_space, is_push_clientid, calibration,get_crash_logs } from '../utils/pageInfo.uts'
import { Config } from "../config";

export class Stat {
  static __stat_instance : Stat | null = null;
  static is_register : boolean = false
  static no_space : boolean = false
  // 上报逻辑实例
  report : Report;
  // 使用单例，只初始化一次
  static getInstance() : Stat {
    // 获取服务空间配置信息
    let space = get_space(uniCloud.config)
    if (Report.uniCloudInstance == null) {
      // 判断不为空对象
      if (space != null) {
        // 重新构造 uniCloud
        let spaceData : UniCloudInitOptions = {
          provider: space.provider,
          spaceId: space.spaceId,
          clientSecret: space.clientSecret,
        }
        const endpoint = space.endpoint
        if (endpoint != null) {
          spaceData.endpoint = space.endpoint
        }

        // 支付宝单独处理一些参数
        if (space.provider == 'alipay') {
          spaceData.secretKey = space.secretKey
          spaceData.accessKey = space.accessKey
          spaceData.spaceAppId = space.spaceAppId
        }

        // 初始化 uniCloud
        // @ts-ignore
        Report.uniCloudInstance = uniCloud.init(spaceData)

      } else {
        if (!Stat.no_space) {
          // #ifdef APP-IOS
          console.error('应用已集成uni统计，但未关联服务空间，请在uniCloud目录右键关联服务空间')
          // #endif
          // #ifndef APP-IOS
          console.log("\u001b[31m应用已集成uni统计，但未关联服务空间，请在uniCloud目录右键关联服务空间\u001b[0m")
          // #endif
          Stat.no_space = true
        }
      }
    }

    // 实例化统计sdk ，要在 实例 unicloud 之后进行，避免 Report 无法拿到 uniCloud 实例
    if (this.__stat_instance == null) {
      this.__stat_instance = new Stat()
    }

    return this.__stat_instance as Stat
  }


  // 当前生命周期内的页面或应用实例
  appInstance ?: Page | null = null

  private isHide : boolean = false
  constructor() {
    this.report = new Report()
  }

  /**
   * 初始化插件参数
   * @param {Object} options
   */
  init(options : UTSJSONObject) {
    // 插件挂载玩成，可以进行后续操作
    Stat.is_register = true
    // 参数处理
    Config.setOptions({ ...options } as UniStatOptions)
    const uniStatConfig = Config.getOptions()
    // 设置上报周期时间
    this.report.eportInterval = uniStatConfig.reportInterval ?? 10

		// #ifdef APP
		// 获取崩溃日志
		get_crash_logs((logs)=>{
			this.registerEvent(StatType.Crash, null, logs)
		})
		// #endif
  }
  /**
   * 应用启动
   * @param {OnLaunchOptions} options 应用参数
   * @param {ComponentPublicInstance} appInstance 应用实例
   */
  // options : OnLaunchOptions, appInstance : ComponentPublicInstance
  onLaunch(options : OnLaunchOptions, appInstance : ComponentPublicInstance) {
    // 注册事件 onLaunch ,需要手动触发
    // this.registerEvent(StatType.LifeCycleLaunch, appInstance, options as any)
  }
  /**
   * 页面加载
   * @param {ComponentPublicInstance} appInstance 应用实例
   */
  onLoad(appInstance : Page) {
    this.registerEvent(StatType.LifeCycleLoad, appInstance)
  }
  /**
   * 显示页面或应用进入前台
   * @param {ComponentPublicInstance} appInstance 应用实例
   */
  onShow(appInstance : Page) {
    this.isHide = false
    // @ts-ignore
    const mptype = is_page(appInstance)
    // 页面执行，应用需要手动调用
    if (mptype) {
      this.registerEvent(StatType.LifeCyclePageShow, appInstance, null)
    }
    // const life_type = mptype == 'app' ? StatType.LifeCycleAppShow : StatType.LifeCyclePageShow
    // this.registerEvent(life_type, appInstance, null)
  }

  /**
   * 页面隐藏或应用进入后台
   * @param {ComponentPublicInstance} appInstance 应用实例
   */
  onHide(appInstance : Page) {

    this.isHide = true
    // @ts-ignore
    const mptype = is_page(appInstance)

    // 页面执行，应用需要手动调用
    if (mptype) {
      this.registerEvent(StatType.LifeCyclePageHide, appInstance, null)
    }
    // const life_type = mptype == 'app' ? StatType.LifeCycleAppHide : StatType.LifeCyclePageHide
    // this.registerEvent(life_type, appInstance, null)
  }

  /**
   * 卸载页面
   * @param {ComponentPublicInstance} appInstance 应用实例
   */
  onUnload(appInstance : Page) {
    // 如果 isHide 为true 说明页面隐藏了，不走卸载逻辑，如果走卸载逻辑，isHide 必不可能是true
    if (this.isHide) {
      this.isHide = false
      return
    }
    this.registerEvent(StatType.LifeCyclePageUnLoad, appInstance, null)
  }

  /**
   * 错误
   * @param {String} error 应用实例
   */
  onError(error : string) {
    // 单独处理错误上报
    this.error(error)
  }

  /**
   * 获取推送ID
   */
  // pushEvent(options : any) {
  //   // TODO uni x 暂不支持，如需要开启，请放开注释
  //   const ClientID = is_push_clientid()
  //   if (ClientID) {
  //     uni.getPushClientId({
  //       success: (res) => {
  //         const cid = res.cid
  //         //  只有获取到才会上传
  //         // if (cid != null) {
  //         this.report.sendPushRequest(options, cid)
  //         // }
  //       },
  //     } as GetPushClientIdOptions)
  //   }
  // }

  /**
   * 注册事件
   * @param {number} EventType 事件类型
   * @param {Page} appInstance	当前页面实例
   * @param {UTSJSONObject} options 应用参数
   */
  registerEvent(EventType : number, appInstance : Page | null, options : any | null = null, error : any | null = '') {
    this.appInstance = appInstance
    // 是否要上报页面数据
    const isPageReport = is_page_report()
    switch (EventType) {
      case StatType.LifeCycleLaunch:
        // 使用非空断言，options在这里肯定非空
        this.report.launch(options!)
        // this.pushEvent(options)
        break
      case StatType.LifeCycleAppShow:
        // TODO 目前只兼容 web 和 app ，小程序等平台需要调用 api onAppHide
        this.report.appShow()
        break
      case StatType.LifeCycleAppHide:
        this.report.appHide(true)
        break
      case StatType.LifeCycleLoad:
        break
      case StatType.LifeCyclePageShow:
        if (isPageReport) {
          this.report.pageShow(appInstance!)
        }
        break
      case StatType.LifeCyclePageHide:
        if (isPageReport) {
          this.report.pageHide(appInstance!)
        }
        break
      case StatType.LifeCyclePageUnLoad:
        if (isPageReport) {
          this.report.pageHide(appInstance!)
        }
        break
      case StatType.LifeCycleError:
        if (error != null) {
          this.report.appError(error)
        }
        break
			case StatType.Crash:
			    this.report.appCrash(options as string[])
			  break
    }
  }

  error(em : string) {
    // 生命周期监听，暂时无用，需要手动调用api
  }
  // 自定义参数上报
  appEvent(name : string, options : any | null = null, fn : ErrorCallback) {
    if (Stat.no_space) {
      fn(false, 61000 as ReportErrorCode)
      return
    }
    if (!Stat.is_register) {
      fn(false, 61001 as ReportErrorCode)
      return
    }
    // const names = ['uni-app-launch', 'uni-app-show', 'uni-app-hide', 'uni-app-error']
    // if (names.indexOf(name) <= -1) {
    // 	// console.error('uniStatReport 事件名不存在，请检查！');
    // 	fn(false, 'uniStatReport 事件名不存在，请检查！')
    // 	return
    // }
    if (name == 'uni-app-launch' && options == null) {
      fn(false, 61002 as ReportErrorCode)
      return
    }

    if (name == 'uni-app-launch') {
      this.registerEvent(StatType.LifeCycleLaunch, null, options)
      // 61001 占位，无实际用途
      fn(true, 61001 as ReportErrorCode)
      return
    }
    if (name == 'uni-app-show') {
      this.registerEvent(StatType.LifeCycleAppShow, null, null)
      // 61001 占位，无实际用途
      fn(true, 61001 as ReportErrorCode)
      return
    }
    if (name == 'uni-app-hide') {
      this.registerEvent(StatType.LifeCycleAppHide, null, null)
      // 61001 占位，无实际用途
      fn(true, 61001 as ReportErrorCode)
      return
    }

    if (name == 'uni-page-show') {
      this.report.pageShow(options as Page)
      // 61001 占位，无实际用途
      fn(true, 61001 as ReportErrorCode)
      return
    }

    if (name == 'uni-page-hide') {
      this.report.pageHide(options as Page)
      // 61001 占位，无实际用途
      fn(true, 61001 as ReportErrorCode)
      return
    }

    if (name == 'uni-app-error') {
      this.registerEvent(StatType.LifeCycleError, null, null, options)
      // 61001 占位，无实际用途
      fn(true, 61001 as ReportErrorCode)
      return
    }

    // 校验 type 参数
    const is_calibration = calibration(name, options)
    if (is_calibration != null) {
      fn(false, is_calibration)
      return
    }

    if (name === 'title') {
      this.report._navigationBarTitle.report = (options as string)
    }

    const value = (typeof options === 'object' ? JSON.stringify(options) : options) as string
    const data : EventParams = {
      key: name,
      value: value as string,
    }
    this.report.sendEventRequest(data)
    // 61001 占位，无实际用途
    fn(true, 61001 as ReportErrorCode)
  }
}
