import { version } from '../package.json';

const STAT_VERSION = version;
const STAT_URL = 'https://tongji.dcloud.io/uni/stat';
const STAT_H5_URL = 'https://tongji.dcloud.io/uni/stat.gif'; 
const PAGE_PVER_TIME = 1800;
const APP_PVER_TIME = 300;
const OPERATING_TIME = 10;
const DIFF_TIME = 60 * 1000 * 60 * 24;

const statConfig = require('uni-stat-config').default || require('uni-stat-config');
const UUID_KEY = '__DC_STAT_UUID';
const UUID_VALUE = '__DC_UUID_VALUE';

function getUuid() {
  let uuid = '';
  if (getPlatformName() === 'n') {
    try {
      uuid = plus.runtime.getDCloudId();
    } catch (e) {
      uuid = '';
    }
    return uuid
  }

  try {
    uuid = uni.getStorageSync(UUID_KEY);
  } catch (e) {
    uuid = UUID_VALUE;
  }

  if (!uuid) {
    uuid = Date.now() + '' + Math.floor(Math.random() * 1e7);
    try {
      uni.setStorageSync(UUID_KEY, uuid);
    } catch (e) {
      uni.setStorageSync(UUID_KEY, UUID_VALUE);
    }
  }
  return uuid;
}

const getSgin = (statData) => {
  let arr = Object.keys(statData);
  let sortArr = arr.sort();
  let sgin = {};
  let sginStr = '';
  for (var i in sortArr) {
    sgin[sortArr[i]] = statData[sortArr[i]];
    sginStr += sortArr[i] + '=' + statData[sortArr[i]] + '&';
  }
  // const options = sginStr.substr(0, sginStr.length - 1)
  // sginStr = sginStr.substr(0, sginStr.length - 1) + '&key=' + STAT_KEY;
  // const si = crypto.createHash('md5').update(sginStr).digest('hex');
  return {
    sign: '',
    options: sginStr.substr(0, sginStr.length - 1)
  };
};

const getSplicing = (data) => {
  let str = '';
  for (var i in data) {
    str += i + '=' + data[i] + '&';
  }
  return str.substr(0, str.length - 1)
};

const getTime = () => {
  return parseInt(new Date().getTime() / 1000);
};

const getPlatformName = () => {
  const platformList = {
    'app-plus': 'n',
    'h5': 'h5',
    'mp-weixin': 'wx',
    'mp-alipay': 'ali',
    'mp-baidu': 'bd',
    'mp-toutiao': 'tt',
    'mp-qq': 'qq'
  };
  return platformList[process.env.VUE_APP_PLATFORM];
};

const getPackName = () => {
  let packName = '';
  if (getPlatformName() === 'wx' || getPlatformName() === 'qq') {
    // 兼容微信小程序低版本基础库
    if (uni.canIUse('getAccountInfoSync')) {
      packName = uni.getAccountInfoSync().miniProgram.appId || '';
    }
  }
  return packName
};

const getVersion = () => {
  return getPlatformName() === 'n' ? plus.runtime.version : '';
};

const getChannel = () => {
  const platformName = getPlatformName();
  let channel = '';
  if (platformName === 'n') {
    channel = plus.runtime.channel;
  }
  return channel;
};

const getScene = (options) => {
  const platformName = getPlatformName();
  let scene = '';
  if (options) {
    return options;
  }
  if (platformName === 'wx') {
    scene = uni.getLaunchOptionsSync().scene;
  }
  return scene;
};
const First__Visit__Time__KEY = 'First__Visit__Time';
const Last__Visit__Time__KEY = 'Last__Visit__Time';

const getFirstVisitTime = () => {
  const timeStorge = uni.getStorageSync(First__Visit__Time__KEY);
  let time = 0;
  if (timeStorge) {
    time = timeStorge;
  } else {
    time = getTime();
    uni.setStorageSync(First__Visit__Time__KEY, time);
    uni.removeStorageSync(Last__Visit__Time__KEY);
  }
  return time;
};

const getLastVisitTime = () => {
  const timeStorge = uni.getStorageSync(Last__Visit__Time__KEY);
  let time = 0;
  if (timeStorge) {
    time = timeStorge;
  } else {
    time = '';
  }
  uni.setStorageSync(Last__Visit__Time__KEY, getTime());
  return time;
};


const PAGE_RESIDENCE_TIME = '__page__residence__time';
let First_Page_residence_time = 0;
let Last_Page_residence_time = 0;


const setPageResidenceTime = () => {
  First_Page_residence_time = getTime();
  if (getPlatformName() === 'n') {
    uni.setStorageSync(PAGE_RESIDENCE_TIME, getTime());
  }
  return First_Page_residence_time
};

const getPageResidenceTime = () => {
  Last_Page_residence_time = getTime();
  if (getPlatformName() === 'n') {
    First_Page_residence_time = uni.getStorageSync(PAGE_RESIDENCE_TIME);
  }
  return Last_Page_residence_time - First_Page_residence_time
};
const TOTAL__VISIT__COUNT = 'Total__Visit__Count';
const getTotalVisitCount = () => {
  const timeStorge = uni.getStorageSync(TOTAL__VISIT__COUNT);
  let count = 1;
  if (timeStorge) {
    count = timeStorge;
    count++;
  }
  uni.setStorageSync(TOTAL__VISIT__COUNT, count);
  return count;
};

const GetEncodeURIComponentOptions = (statData) => {
  let data = {};
  for (let prop in statData) {
    data[prop] = encodeURIComponent(statData[prop]);
  }
  return data;
};

let Set__First__Time = 0;
let Set__Last__Time = 0;

const getFirstTime = () => {
  let time = new Date().getTime();
  Set__First__Time = time;
  Set__Last__Time = 0;
  return time;
};


const getLastTime = () => {
  let time = new Date().getTime();
  Set__Last__Time = time;
  return time;
};


const getResidenceTime = (type) => {
  let residenceTime = 0;
  if (Set__First__Time !== 0) {
    residenceTime = Set__Last__Time - Set__First__Time;
  }

  residenceTime = parseInt(residenceTime / 1000);
  residenceTime = residenceTime < 1 ? 1 : residenceTime;
  if (type === 'app') {
    let overtime = residenceTime > APP_PVER_TIME ? true : false;
    return {
      residenceTime,
      overtime
    };
  }
  if (type === 'page') {
    let overtime = residenceTime > PAGE_PVER_TIME ? true : false;
    return {
      residenceTime,
      overtime
    };
  }

  return {
    residenceTime
  };

};

const getRoute = () => {
  var pages = getCurrentPages();
  var page = pages[pages.length - 1];
  let _self = page.$vm;

  if (getPlatformName() === 'bd') {
    return _self.$mp && _self.$mp.page.is;
  } else {
    return (_self.$scope && _self.$scope.route) || (_self.$mp && _self.$mp.page.route);
  }
};

const getPageRoute = (self) => {
  var pages = getCurrentPages();
  var page = pages[pages.length - 1];
  let _self = page.$vm;
  let query = self._query;
  let str = query && JSON.stringify(query) !== '{}' ? '?' + JSON.stringify(query) : '';
  // clear
  self._query = '';
  if (getPlatformName() === 'bd') {
    return _self.$mp && _self.$mp.page.is + str;
  } else {
    return (_self.$scope && _self.$scope.route + str) || (_self.$mp && _self.$mp.page.route + str);
  }
};

const getPageTypes = (self) => {
  if (self.mpType === 'page' || (self.$mp && self.$mp.mpType === 'page') || self.$options.mpType === 'page') {
    return true;
  }
  return false;
};

const calibration = (eventName, options) => {
  //  login 、 share 、pay_success 、pay_fail 、register 、title
  if (!eventName) {
    console.error(`uni.report 缺少 [eventName] 参数`);
    return true
  }
  if (typeof eventName !== 'string') {
    console.error(`uni.report [eventName] 参数类型错误,只能为 String 类型`);
    return true
  }
  if (eventName.length > 255) {
    console.error(`uni.report [eventName] 参数长度不能大于 255`);
    return true
  }

  if (typeof options !== 'string' && typeof options !== 'object') {
    console.error(`uni.report [options] 参数类型错误,只能为 String 或 Object 类型`);
    return true
  }

  if (typeof options === 'string' && options.length > 255) {
    console.error(`uni.report [options] 参数长度不能大于 255`);
    return true
  }

  if (eventName === 'title' && typeof options !== 'string') {
    console.error('uni.report [eventName] 参数为 title 时，[options] 参数只能为 String 类型');
    return true
  }
};

const Report_Data_Time = 'Report_Data_Time';
const Report_Status = 'Report_Status';
const isReportData = () => {
  return new Promise((resolve, reject) => {
    let start_time = '';
    let end_time = new Date().getTime();
    let diff_time = DIFF_TIME;
    let report_status = 1;
    try {
      start_time = uni.getStorageSync(Report_Data_Time);
      report_status = uni.getStorageSync(Report_Status);
    } catch (e) {
      start_time = '';
      report_status = 1;
    }

    if (report_status === '') {
      requestData(({
        enable
      }) => {
        uni.setStorageSync(Report_Data_Time, end_time);
        uni.setStorageSync(Report_Status, enable);
        if (enable === 1) {
          resolve();
        }
      });
      return
    }

    if (report_status === 1) {
      resolve();
    }

    if (!start_time) {
      uni.setStorageSync(Report_Data_Time, end_time);
      start_time = end_time;
    }

    if ((end_time - start_time) > diff_time) {
      requestData(({
        enable
      }) => {
        uni.setStorageSync(Report_Data_Time, end_time);
        uni.setStorageSync(Report_Status, enable);
      });
    }

  })
};

const requestData = (done) => {
  let formData = {
    usv: STAT_VERSION,
    conf: JSON.stringify({
      ak: statConfig.appid
    })
  };
  uni.request({
    url: STAT_URL,
    method: 'GET',
    data: formData,
    success: (res) => {
      const {
        data
      } = res;
      if (data.ret === 0) {
        typeof done === 'function' && done({
          enable: data.enable
        });
      }
    },
    fail: (e) => {
      let report_status_code = 1;
      try {
        report_status_code = uni.getStorageSync(Report_Status);
      } catch (e) {
        report_status_code = 1;
      }
      if (report_status_code === '') {
        report_status_code = 1;
      }
      if (report_status_code === 1) {
        typeof done === 'function' && done({
          enable: res.enable
        });
      }
      // console.error('统计请求错误');
    }
  });
};

const PagesJson = require('uni-pages?{"type":"style"}').default;
const statConfig$1 = require('uni-stat-config').default || require('uni-stat-config');

const resultOptions = uni.getSystemInfoSync();

class Util {
  constructor() {
    this.self = '';
    this._retry = 0;
    this._platform = '';
    this._query = {};
    this._navigationBarTitle = {
      config: '',
      page: '',
      report: '',
      lt: ''
    };
    this._operatingTime = 0;
    this._reportingRequestData = {
      '1': [],
      '11': []
    };
    this.__prevent_triggering = false;

    this.__licationHide = false;
    this.__licationShow = false;
    this._lastPageRoute = '';
    this.statData = {
      uuid: getUuid(),
      ut: getPlatformName(),
      mpn: getPackName(),
      ak: statConfig$1.appid,
      usv: STAT_VERSION,
      v: getVersion(),
      ch: getChannel(),
      cn: '',
      pn: '',
      ct: '',
      t: getTime(),
      tt: '',
      p: resultOptions.platform === 'android' ? 'a' : 'i',
      brand: resultOptions.brand || '',
      md: resultOptions.model,
      sv: resultOptions.system.replace(/(Android|iOS)\s/, ''),
      mpsdk: resultOptions.SDKVersion || '',
      mpv: resultOptions.version || '',
      lang: resultOptions.language,
      pr: resultOptions.pixelRatio,
      ww: resultOptions.windowWidth,
      wh: resultOptions.windowHeight,
      sw: resultOptions.screenWidth,
      sh: resultOptions.screenHeight
    };

  }

  getIsReportData() {
    return isReportData()
  }

  _applicationShow() {
    if (this.__licationHide) {
      getLastTime();
      const time = getResidenceTime('app');
      if (time.overtime) {
        let options = {
          path: this._lastPageRoute,
          scene: this.statData.sc
        };
        this._sendReportRequest(options);
      }
      this.__licationHide = false;
    }
  }

  _applicationHide(self, type) {

    this.__licationHide = true;
    getLastTime();
    const time = getResidenceTime();
    getFirstTime();
    const route = getPageRoute(this);
    this._sendHideRequest({
      urlref: route,
      urlref_ts: time.residenceTime
    }, type);
  }

  _pageShow() {
    const route = getPageRoute(this);
    const routepath = getRoute();
    this._navigationBarTitle.config = PagesJson &&
      PagesJson.pages[routepath] &&
      PagesJson.pages[routepath].titleNView &&
      PagesJson.pages[routepath].titleNView.titleText ||
      PagesJson &&
      PagesJson.pages[routepath] &&
      PagesJson.pages[routepath].navigationBarTitleText || '';

    if (this.__licationShow) {
      getFirstTime();
      this.__licationShow = false;
      // console.log('这是 onLauch 之后执行的第一次 pageShow ，为下次记录时间做准备');
      this._lastPageRoute = route;
      return;
    }

    getLastTime();
    this._lastPageRoute = route;
    const time = getResidenceTime('page');
    if (time.overtime) {
      let options = {
        path: this._lastPageRoute,
        scene: this.statData.sc
      };
      this._sendReportRequest(options);
    }
    getFirstTime();
  }

  _pageHide() {
    if (!this.__licationHide) {
      getLastTime();
      const time = getResidenceTime('page');
      this._sendPageRequest({
        url: this._lastPageRoute,
        urlref: this._lastPageRoute,
        urlref_ts: time.residenceTime
      });
      this._navigationBarTitle = {
        config: '',
        page: '',
        report: '',
        lt: ''
      };
      return;
    }
  }

  _login() {
    this._sendEventRequest({
      key: 'login'
    }, 0);
  }

  _share() {
    this._sendEventRequest({
      key: 'share'
    }, 0);
  }
  _payment(key) {
    this._sendEventRequest({
      key
    }, 0);
  }
  _sendReportRequest(options) {

    this._navigationBarTitle.lt = '1';
    let query = options.query && JSON.stringify(options.query) !== '{}' ? '?' + JSON.stringify(options.query) : '';
    this.statData.lt = '1';
    this.statData.url = (options.path + query) || '';
    this.statData.t = getTime();
    this.statData.sc = getScene(options.scene);
    this.statData.fvts = getFirstVisitTime();
    this.statData.lvts = getLastVisitTime();
    this.statData.tvc = getTotalVisitCount();
    if (getPlatformName() === 'n') {
      this.getProperty();
    } else {
      this.getNetworkInfo();
    }
  }

  _sendPageRequest(opt) {
    let {
      url,
      urlref,
      urlref_ts
    } = opt;
    this._navigationBarTitle.lt = '11';
    let options = {
      ak: this.statData.ak,
      uuid: this.statData.uuid,
      lt: '11',
      ut: this.statData.ut,
      url,
      tt: this.statData.tt,
      urlref,
      urlref_ts,
      ch: this.statData.ch,
      usv: this.statData.usv,
      t: getTime(),
      p: this.statData.p
    };
    this.request(options);
  }

  _sendHideRequest(opt, type) {
    let {
      urlref,
      urlref_ts
    } = opt;
    let options = {
      ak: this.statData.ak,
      uuid: this.statData.uuid,
      lt: '3',
      ut: this.statData.ut,
      urlref,
      urlref_ts,
      ch: this.statData.ch,
      usv: this.statData.usv,
      t: getTime(),
      p: this.statData.p
    };
    this.request(options, type);
  }
  _sendEventRequest({
    key = '',
    value = ""
  } = {}) {
    const route = this._lastPageRoute;
    let options = {
      ak: this.statData.ak,
      uuid: this.statData.uuid,
      lt: '21',
      ut: this.statData.ut,
      url: route,
      ch: this.statData.ch,
      e_n: key,
      e_v: typeof(value) === 'object' ? JSON.stringify(value) : value.toString(),
      usv: this.statData.usv,
      t: getTime(),
      p: this.statData.p
    };
    this.request(options);
  }

  getNetworkInfo() {
    uni.getNetworkType({
      success: (result) => {
        this.statData.net = result.networkType;
        this.getLocation();
      }
    });
  }

  getProperty() {
    plus.runtime.getProperty(plus.runtime.appid, (wgtinfo) => {
      this.statData.v = wgtinfo.version || '';
      this.getNetworkInfo();
    });
  }

  getLocation() {
    if (statConfig$1.getLocation) {
      uni.getLocation({
        type: 'wgs84',
        geocode: true,
        success: (result) => {
          if (result.address) {
            this.statData.cn = result.address.country;
            this.statData.pn = result.address.province;
            this.statData.ct = result.address.city;
          }

          this.statData.lat = result.latitude;
          this.statData.lng = result.longitude;
          this.request(this.statData);
        }
      });
    } else {
      this.statData.lat = 0;
      this.statData.lng = 0;
      this.request(this.statData);
    }
  }

  request(data, type) {
    let time = getTime();
    const title = this._navigationBarTitle;
    data.ttn = title.page;
    data.ttpj = title.config;
    data.ttc = title.report;

    let requestData = this._reportingRequestData;
    if (getPlatformName() === 'n') {
      requestData = uni.getStorageSync('__UNI__STAT__DATA') || {};
    }
    if (!requestData[data.lt]) {
      requestData[data.lt] = [];
    }
    requestData[data.lt].push(data);

    if (getPlatformName() === 'n') {
      uni.setStorageSync('__UNI__STAT__DATA', requestData);
    }
    if (getPageResidenceTime() < OPERATING_TIME && !type) {
      return
    }
    let uniStatData = this._reportingRequestData;
    if (getPlatformName() === 'n') {
      uniStatData = uni.getStorageSync('__UNI__STAT__DATA');
    }
    // 时间超过，重新获取时间戳
    setPageResidenceTime();
    let firstArr = [];
    let contentArr = [];
    let lastArr = [];

    for (let i in uniStatData) {
      const rd = uniStatData[i];
      rd.forEach((elm) => {
        const newData = getSplicing(elm);
        if (i === 0) {
          firstArr.push(newData);
        } else if (i === 3) {
          lastArr.push(newData);
        } else {
          contentArr.push(newData);
        }
      });
    }

    firstArr.push(...contentArr, ...lastArr);
    let optionsData = {
      usv: STAT_VERSION, //统计 SDK 版本号
      t: time, //发送请求时的时间戮
      requests: JSON.stringify(firstArr),
    };

    this._reportingRequestData = {};
    if (getPlatformName() === 'n') {
      uni.removeStorageSync('__UNI__STAT__DATA');
    }

    if (data.ut === 'h5') {
      this.imageRequest(optionsData);
      return
    }

    if (getPlatformName() === 'n' && this.statData.p === 'a') {
      setTimeout(() => {
        this._sendRequest(optionsData);
      }, 200);
      return
    }
    this._sendRequest(optionsData);
  }
  _sendRequest(optionsData) {
    this.getIsReportData().then(() => {
      uni.request({
        url: STAT_URL,
        method: 'POST',
        // header: {
        //   'content-type': 'application/json' // 默认值
        // },
        data: optionsData,
        success: () => {
          // if (process.env.NODE_ENV === 'development') {
          //   console.log('stat request success');
          // }
        },
        fail: (e) => {
          if (++this._retry < 3) {
            setTimeout(() => {
              this._sendRequest(optionsData);
            }, 1000);
          }
        }
      });
    });
  }
  /**
   * h5 请求
   */
  imageRequest(data) {
    this.getIsReportData().then(() => {
      let image = new Image();
      let options = getSgin(GetEncodeURIComponentOptions(data)).options;
      image.src = STAT_H5_URL + '?' + options;
    });
  }

  sendEvent(key, value) {
    // 校验 type 参数
    if (calibration(key, value)) return

    if (key === 'title') {
      this._navigationBarTitle.report = value;
      return
    }
    this._sendEventRequest({
      key,
      value: typeof(value) === 'object' ? JSON.stringify(value) : value
    }, 1);
  }
}


class Stat extends Util {
  static getInstance() {
    if (!this.instance) {
      this.instance = new Stat();
    }
    return this.instance;
  }
  constructor() {
    super();
    this.instance = null;
    // 注册拦截器
    if (typeof uni.addInterceptor === 'function' && process.env.NODE_ENV !== 'development') {
      this.addInterceptorInit();
      this.interceptLogin();
      this.interceptShare(true);
      this.interceptRequestPayment();
    }
  }

  addInterceptorInit() {
    let self = this;
    uni.addInterceptor('setNavigationBarTitle', {
      invoke(args) {
        self._navigationBarTitle.page = args.title;
      }
    });
  }

  interceptLogin() {
    let self = this;
    uni.addInterceptor('login', {
      complete() {
        self._login();
      }
    });
  }

  interceptShare(type) {
    let self = this;
    if (!type) {
      self._share();
      return
    }
    uni.addInterceptor('share', {
      success() {
        self._share();
      },
      fail() {
        self._share();
      }
    });
  }

  interceptRequestPayment() {
    let self = this;
    uni.addInterceptor('requestPayment', {
      success() {
        self._payment('pay_success');
      },
      fail() {
        self._payment('pay_fail');
      }
    });
  }

  report(options, self) {
    this.self = self;
    // if (process.env.NODE_ENV === 'development') {
    //   console.log('report init');
    // }
    setPageResidenceTime();
    this.__licationShow = true;
    this._sendReportRequest(options, true);
  }

  load(options, self) {
    if (!self.$scope && !self.$mp) {
      const page = getCurrentPages();
      self.$scope = page[page.length - 1];
    }
    this.self = self;
    this._query = options;
  }

  show(self) {
    this.self = self;
    if (getPageTypes(self)) {
      this._pageShow(self);
    } else {
      this._applicationShow(self);
    }
  }

  ready(self) {
    // this.self = self;
    // if (getPageTypes(self)) {
    //   this._pageShow(self);
    // }
  }
  hide(self) {
    this.self = self;
    if (getPageTypes(self)) {
      this._pageHide(self);
    } else {
      this._applicationHide(self, true);
    }
  }
  error(em) {
    if (this._platform === 'devtools') {
      if (process.env.NODE_ENV === 'development') {
        console.info('当前运行环境为开发者工具，不上报数据。');
      }
      // return;
    }
    let emVal = '';
    if (!em.message) {
      emVal = JSON.stringify(em);
    } else {
      emVal = em.stack;
    }
    let options = {
      ak: this.statData.ak,
      uuid: this.statData.uuid,
      lt: '31',
      ut: this.statData.ut,
      ch: this.statData.ch,
      mpsdk: this.statData.mpsdk,
      mpv: this.statData.mpv,
      v: this.statData.v,
      em: emVal,
      usv: this.statData.usv,
      t: getTime(),
      p: this.statData.p
    };
    this.request(options);
  }
}

const stat = Stat.getInstance();
let isHide = false;
const lifecycle = {
  onLaunch(options) {
    stat.report(options, this);
  },
  onReady() {
    stat.ready(this);
  },
  onLoad(options) {
    stat.load(options, this);
    // 重写分享，获取分享上报事件
    if (this.$scope && this.$scope.onShareAppMessage) {
      let oldShareAppMessage = this.$scope.onShareAppMessage;
      this.$scope.onShareAppMessage = function(options) {
        stat.interceptShare(false);
        return oldShareAppMessage.call(this, options)
      };
    }
  },
  onShow() {
    isHide = false;
    stat.show(this);
  },
  onHide() {
    isHide = true;
    stat.hide(this);
  },
  onUnload() {
    if (isHide) {
      isHide = false;
      return
    }
    stat.hide(this);
  },
  onError(e) {
    stat.error(e);
  }
};

function main() {
  if (process.env.NODE_ENV === 'development') {
    uni.report = function(type, options) {};
  } else {
    const Vue = require('vue');
    (Vue.default || Vue).mixin(lifecycle);
    uni.report = function(type, options) {
      stat.sendEvent(type, options);
    };
  }
}

main();
