// app.js
const api = require('./api/index.js');
App({
  globalData: {
    socketTask: null,
    isConnected: false,
    reconnectTimer: null,
    heartbeatTimer: null,
    currentWorkorderId: '',
    userInfo: wx.getStorageSync('user') || {}
  },

  onLaunch() {
    this.initWebSocketService();
    wx.onAppShow(() => this.handleAppShow());
    wx.onAppHide(() => this.handleAppHide());

    this.locationService = {
      isTracking: false,
      currentWorkorderId: '',
      isLocationUpdateStarted: false
    };

    // 司机自动启动【普通实时定位上传】
    const { operationRole } = this.globalData.userInfo;
    if (operationRole === 4) {
      this.startDriverRealTimeLocation();
    }
  },

  initWebSocketService() {
    if (!this.wsService) {
      this.wsService = {
        connect: (url) => {
          const that = this;
          if (that.globalData.socketTask) {
            that.wsService.close();
          }

          const socketTask = wx.connectSocket({ url, header: { 'content-type': 'application/json' } });

          socketTask.onOpen(() => {
            that.globalData.isConnected = true;
            that.globalData.socketTask = socketTask;
            that.clearReconnectTimer();
            if (that.globalData.currentWorkorderId) {
              that.wsService.send({ type: 'subscribe', workorderId: that.globalData.currentWorkorderId });
            }
            wx.$emit('socketOpen');
          });

          socketTask.onMessage((res) => {
            try {
              const message = JSON.parse(res.data);
              wx.$emit('wsMessage', message);
            } catch (err) { }
          });

          socketTask.onClose((res) => {
            that.globalData.isConnected = false;
            that.globalData.socketTask = null;
            that.stopHeartbeat();
            if (res.code !== 1000) that.startReconnect();
          });

          socketTask.onError((err) => {
            that.globalData.isConnected = false;
            that.globalData.socketTask = null;
            that.stopHeartbeat();
          });
        },

        send: (data) => {
          const that = this;
          if (that.globalData.isConnected && that.globalData.socketTask) {
            that.globalData.socketTask.send({
              data: JSON.stringify(data),
              fail: (err) => console.error('发送失败', err)
            });
          }
        },

        close: (code = 1000, reason = 'normal close') => {
          const that = this;
          if (that.globalData.socketTask) {
            that.globalData.socketTask.close({ code, reason });
          }
        }
      };
    }
  },

  handleAppShow() {
    const that = this;
    if (!that.globalData.isConnected && !that.globalData.reconnectTimer) {
      const { operationId } = that.globalData.userInfo;
      if (!operationId) return;
      const wsUrl = `wss://esos-iot.com:9443/communication/update/${operationId}`;
      that.wsService.connect(wsUrl);
    }
  },

  handleAppHide() { },

  startHeartbeat() {
    const that = this;
    that.stopHeartbeat();
    that.heartbeatTimer = setInterval(() => {
      if (that.globalData.isConnected) {
        that.wsService.send({ type: 'heartbeat', timestamp: Date.now() });
      }
    }, 5000);
  },

  stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  },

  startReconnect() {
    const that = this;
    that.clearReconnectTimer();
    let delay = 1000;
    that.globalData.reconnectTimer = setInterval(() => {
      if (!that.globalData.isConnected) {
        const { operationId } = that.globalData.userInfo;
        if (operationId) {
          const wsUrl = `wss://esos-iot.com:9443/communication/update/${operationId}`;
          that.wsService.connect(wsUrl);
        }
        delay = Math.min(delay * 2, 8000);
      } else {
        that.clearReconnectTimer();
      }
    }, delay);
  },

  clearReconnectTimer() {
    if (this.globalData.reconnectTimer) {
      clearInterval(this.globalData.reconnectTimer);
      this.globalData.reconnectTimer = null;
    }
  },

  /****************************************************************************
   * 1. 司机【普通实时定位】（一直上传，不绑定工单）
   ***************************************************************************/
  startDriverRealTimeLocation() {
    const { operationRole } = this.globalData.userInfo;
    if (operationRole !== 4) return;

    const service = this.locationService;
    this._removeLocationListener();

    const startLocationApi = wx.startLocationUpdateBackground || wx.startLocationUpdate;
    startLocationApi({
      type: 'gcj02',
      success: () => {
        service.isLocationUpdateStarted = true;
        let lastLocation = null;
        const DISTANCE_THRESHOLD = 5;

        wx.onLocationChange((location) => {
          // 距离过滤
          if (lastLocation) {
            const distance = this.calculateDistance(
              lastLocation.latitude, lastLocation.longitude,
              location.latitude, location.longitude
            );
            if (distance < DISTANCE_THRESHOLD) return;
          }
          lastLocation = location;

          // 统一上传：实时位置 + 有工单就工单一起传
          this._uploadRealTimeLocation(location);
          if (service.currentWorkorderId) {
            this._uploadWorkorderLocation(location, service.currentWorkorderId);
          }
        });
      }
    });
  },

  /****************************************************************************
   * 2. 司机【开始执行工单】（绑定工单，额外上传工单位置）
   ***************************************************************************/
  startDriverWorkorderLocation(workorderId) {
    if (!workorderId) return;
    const service = this.locationService;
    service.currentWorkorderId = workorderId;
  },

  /****************************************************************************
   * 3. 停止工单定位（只停止工单，不影响实时定位上传）
   ***************************************************************************/
  stopDriverWorkorderLocation() {
    const service = this.locationService;
    service.currentWorkorderId = '';
  },

  /****************************************************************************
   * 上传：司机实时位置（一直传）
   ***************************************************************************/
  _uploadRealTimeLocation(location) {
    const { operationRole } = this.globalData.userInfo;
    if (operationRole !== 4) return;

    const latOk = location.latitude >= 3.86 && location.latitude <= 53.55;
    const lngOk = location.longitude >= 73.66 && location.longitude <= 135.05;
    if (!latOk || !lngOk) return;

    const data = {
      userType: operationRole,
      latitude: location.latitude,
      longitude: location.longitude,
      accuracy: location.accuracy,
      createTime: Date.now()
    };
    api.request('/sysoperation/inseroperationlocation', 'post', data, { isPublic: false })
      .catch(err => console.error('实时位置上传失败', err));
  },

  /****************************************************************************
   * 上传：工单位置（执行工单时才传）
   ***************************************************************************/
  _uploadWorkorderLocation(location, workorderId) {
    const latOk = location.latitude >= 3.86 && location.latitude <= 53.55;
    const lngOk = location.longitude >= 73.66 && location.longitude <= 135.05;
    if (!latOk || !lngOk) return;

    const data = {
      workorderId: workorderId,
      latitude: location.latitude,
      longitude: location.longitude,
      createTime: Date.now(),
      accuracy: location.accuracy
    };
    api.request('/sysworkorder/insercoordinateredis', 'post', data, { isPublic: false })
      .catch(err => console.error('工单位置上传失败', err));
  },

  calculateDistance(lat1, lng1, lat2, lng2) {
    const R = 6371000;
    const radLat1 = lat1 * Math.PI / 180;
    const radLat2 = lat2 * Math.PI / 180;
    const dLat = radLat2 - radLat1;
    const dLng = (lng2 - lng1) * Math.PI / 180;
    const a = Math.sin(dLat / 2) ** 2 + Math.cos(radLat1) * Math.cos(radLat2) * Math.sin(dLng / 2) ** 2;
    return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  },

  _removeLocationListener() {
    if (wx.offLocationChange) wx.offLocationChange();
  }
});

// 全局事件总线
wx.$on = function (eventName, callback) {
  if (!this.$events) this.$events = {};
  if (!this.$events[eventName]) this.$events[eventName] = [];
  this.$events[eventName].push(callback);
};
wx.$emit = function (eventName, data) {
  if (!this.$events || !this.$events[eventName]) return;
  this.$events[eventName].forEach(cb => cb(data));
};
wx.$off = function (eventName, callback) {
  if (!this.$events || !this.$events[eventName]) return;
  if (callback) this.$events[eventName] = this.$events[eventName].filter(cb => cb !== callback);
  else this.$events[eventName] = [];
};