import { v4 as uuidv4 } from 'uuid';
import * as turf from "@turf/turf";

interface ReporStruct {
  // 上报间隔超过一个小时后产生新的reporId，即使浏览器关闭再打开如果不超过一小时也是用旧的
  reportId: string;

  // 用户唯一标识
  userId: string;
  // 归类模块
  tag: string;
  // 模块名称，对应页面路由
  moduleName: string;
  // 用户操作
  action: string;
  // 操作参数
  params: any;

  // 纬度
  latitude: number;
  // 经度
  longitude: number;
  // 操作发生时间戳
  timestamp: number;
  // 是否移动设备
  mobile: boolean;
  userAgent: string;
  platform: string;
}

type CommStr = Pick<ReporStruct, 'reportId' | 'userId' | 'latitude' | 'longitude' | 'mobile' | 'userAgent' | 'platform'>;
class FillingPointSDK {
  private data: CommStr
  private enable: boolean; // 启用/禁用
  private STORAGE_KEY = 'FillingPoint_KEY';
  private timeout = 1000 * 60 * 60;
  private url = '';
  private headers: RequestInit['headers'];

  constructor(config: { url: string; userId: string; platform: string; mobile?: boolean, headers?: RequestInit['headers']; }) {
    this.enable = true;
    this.url = config.url;
    this.headers = config.headers ?? {};

    this.data = {
      reportId: uuidv4(),
      userId: config.userId,
      latitude: -1,
      longitude: -1,
      mobile: config.mobile ?? false,
      userAgent: navigator.userAgent,
      platform: config.platform,
    };

    this.listenerGeoChange();

    if (typeof window !== 'undefined' && !window.FillingPointSDK) {
      // 挂载实例到 window
      window.FillingPointSDK = this;
    }
  }

  listenerGeoChange() {
    navigator.geolocation.watchPosition((succ) => {
      console.log('地理位置变化:', succ);
      const latitude = succ.coords.latitude;
      const longitude = succ.coords.longitude;

      const storage = JSON.parse(localStorage.getItem(this.STORAGE_KEY) ?? '{}');
      const from = turf.point([storage.latitude ?? latitude, storage.longitude ?? longitude]);
      const to = turf.point([latitude, longitude]);
      const distance = turf.distance(from, to); // 千米

      this.setData('latitude', latitude);
      this.setData('longitude', longitude);

      if (distance > 3) {
        const uuid = uuidv4();
        this.setData('reportId', uuid);
        localStorage.setItem(this.STORAGE_KEY, JSON.stringify({ ...storage, reportId: uuid, latitude, longitude }));
      } else if (!storage.latitude && !storage.longitude) {
        localStorage.setItem(this.STORAGE_KEY, JSON.stringify({ ...storage, latitude, longitude }));
      }
    }, () => {}, {});
  }

  getData<T extends keyof CommStr>(key: T): CommStr[T] {
    return this.data[key];
  }

  setData<T extends keyof CommStr>(key: T, value: CommStr[T]) {
    this.data[key] = value;
  }

  setTime(time: number) {
    this.timeout = time;
  }

  disable() {
    this.enable = false;
  }

  repor(tag: string, moduleName: ReporStruct['moduleName'], action: ReporStruct['action'], params: ReporStruct['params'] = '') {
    if (!this.enable) return;

    const timestamp = new Date().getTime();

    window.requestAnimationFrame(() => {
      const storage = JSON.parse(localStorage.getItem(this.STORAGE_KEY) ?? '{}');

      if (timestamp - (storage.timestamp ?? 0) > this.timeout) {
        const uuid = uuidv4();
        this.setData('reportId', uuid);
        localStorage.setItem(this.STORAGE_KEY, JSON.stringify({ ...storage, reportId: uuid, timestamp }));
      } else {
        localStorage.setItem(this.STORAGE_KEY, JSON.stringify({ ...storage, timestamp }));
      }

      const reporData: ReporStruct = {
        tag,
        moduleName,
        action,
        params,
        timestamp,
        ...this.data,
      };

      if (!this.url) {
        return;
      }

      fetch(this.url, {
        method: 'post',
        headers: {
          "Content-Type": "application/json",
          ...this.headers
        },
        body: JSON.stringify(reporData),
      });
    });
  }
}

export default FillingPointSDK;
