import { useState, useCallback, useMemo, useRef, useEffect } from 'react';
import { useLocation } from '@/hooks/system/useLocation';
import { useClockInStore } from '@/stores/clockIn';
import { useAuthStore } from '@/stores/auth';
import { actionType, workingTimeInfo } from '@/api/approve/index.js';
import { collectionDate, oaV2CheckAddress } from '@/api/clock/index.js';
import { cardTypes } from '@/constants/apply.js';
import { useTranslation } from 'react-i18next';
export const useClockIn = () => {
  const { t } = useTranslation('attendance');
  const [clockInBtnLoading, setClockInBtnLoading] = useState(false);
  const { startWatchingLocation, stopWatchingLocation } = useLocation();
  const [isLocationWatching, setIsLocationWatching] = useState(false);
  const lastLocationRef = useRef(null);
  const locationUpdateCallbackRef = useRef(null);
  // 位置更新节流与并发控制引用
  const lastUpdateTimestampRef = useRef(0);
  const pendingCoordsRef = useRef(null);
  const updateInFlightRef = useRef(null);
  const lastAddressUpdateRef = useRef({ t: 0, coords: null });
  const addressErrorCooldownUntilRef = useRef(0);
  // 一次性强制刷新控制（用于下拉刷新重启监听后的首次更新不受节流限制）
  const forceNextUpdateRef = useRef(false);
  const forcedUpdateResolverRef = useRef(null);
  const forcedUpdateTimeoutRef = useRef(null);

  const { 
    setLocation, 

    setActionTypeResult,
    setWorkingTimeResult,
    setCollectionResult,
    setActionCoords,
    // 使用store中的状态
    clockInList,
    loading,
    setClockInList,
    setLoading,
  } = useClockInStore();

  const user = useMemo(() => useAuthStore.getState().getUser(), []);
  const userID = useMemo(() => user?.ID, [user]);

  const updateActionSnapshot = useCallback((coords) => {
    try {
      const addr = useClockInStore.getState()?.location?.addressText || '';
      setActionCoords({ latitude: coords.latitude, longitude: coords.longitude, addressText: addr });
    } catch (_) {}
  }, [setActionCoords]);
  
  // 最小更新阈值（毫秒/米）
  /*
   * 位置与地址更新的节流阈值：
   * - 数据刷新（actionType / workingTime / collection）：时间 OR 距离，满足任一即可触发
   * - 地址逆解析（oaV2CheckAddress）：时间 AND 距离，需同时满足
   * 单位：时间=毫秒，距离=米；首次进入 last.t=0 且 last.coords=null，地址逆解析会立即通过 AND 条件执行一次
   */
  // 数据刷新：最小时间间隔（ms）；与 MIN_DISTANCE_CHANGE_M 为 OR 关系
  const MIN_UPDATE_INTERVAL_MS = 4000;
  // 数据刷新：最小位移（m）；与 MIN_UPDATE_INTERVAL_MS 为 OR 关系；过滤定位抖动
  const MIN_DISTANCE_CHANGE_M = 10;
  // 地址逆解析：最小时间间隔（ms）；与 ADDRESS_MIN_DISTANCE_M 为 AND 关系；控制高成本接口频率
  const ADDRESS_UPDATE_INTERVAL_MS = 15000;
  // 地址逆解析：最小位移（m）；与 ADDRESS_UPDATE_INTERVAL_MS 为 AND 关系；避免无意义地址刷新
  const ADDRESS_MIN_DISTANCE_M = 50;
  // 地址逆解析：失败后的最小重试冷却时间（ms），用于防止连续失败风暴
  const ADDRESS_ERROR_COOLDOWN_MS = 10000;

  /**
   * 计算两经纬度点之间的球面距离（米），采用 Haversine 公式
   * @param {Object} a - 上一位置（prev）：{ latitude:number, longitude:number }
   * @param {Object} b - 当前位置（curr）：{ latitude:number, longitude:number }
   * @returns {number} 距离（米）；若任一参数无效，返回 Infinity（用于强制触发首次更新）
   * 细节：返回 Infinity 的设计让首次定位（prev 无效）被视为“足够远”，从而立即触发一次数据更新
   */
  const computeDistanceMeters = useCallback((a, b) => {
    const isValidCoord = (c) => (
      !!c && typeof c.latitude === 'number' && typeof c.longitude === 'number' &&
      c.latitude >= -90 && c.latitude <= 90 && c.longitude >= -180 && c.longitude <= 180
    );
    if (!isValidCoord(a) || !isValidCoord(b)) return Infinity;
    const toRad = (n) => (n * Math.PI) / 180;
    const R = 6371000; // 地球半径，米
    const dLat = toRad(b.latitude - a.latitude);
    const dLon = toRad(b.longitude - a.longitude);
    const lat1 = toRad(a.latitude);
    const lat2 = toRad(b.latitude);
    const sinDLat = Math.sin(dLat / 2);
    const sinDLon = Math.sin(dLon / 2);
    const aVal = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon;
    const c = 2 * Math.atan2(Math.sqrt(aVal), Math.sqrt(1 - aVal));
    return R * c;
  }, []);

  /**
   * 获取打卡类型和状态
   */
  const getActionType = useCallback(async (coords) => {
    const currentLoc = useClockInStore.getState().location;
    const data = {
      checkMethod: 2,
      staffUID: userID,
      latitude: String(coords?.latitude || currentLoc?.latitude || ''),
      longitude: String(coords?.longitude || currentLoc?.longitude || ''),
    };
    
    const res = await actionType(data);
    if (res.status === 0) {
      return res.data;
    }
    return {};
  }, [userID]);
  /**
   * 获取考勤班次配置信息
   */
  const getWorkingTimeInfo = useCallback(async () => {
    const res = await workingTimeInfo();
    if (res.status === 0) {
      return res.data;
    }
    return {};
  }, []);

  /**
   * 获取当日打卡记录
   */
  const getCollectionDate = useCallback(async () => {
    const res = await collectionDate({ staffUID: userID });
    if (res.status === 0) {
      return res.data;
    }
    return {};
  }, [userID]);

  /**
   * 获取地址信息（带节流：时间与距离双阈值）
   */
  const getTextAddress = useCallback(async (coords) => {
    const now = Date.now();
    // 若处于失败冷却窗口内，直接跳过
    if (now < addressErrorCooldownUntilRef.current) {
      return;
    }

    const last = lastAddressUpdateRef.current;
    const farEnough = !last.coords || computeDistanceMeters(last.coords, coords) >= ADDRESS_MIN_DISTANCE_M;
    const timeEnough = now - last.t >= ADDRESS_UPDATE_INTERVAL_MS;
    if (!(timeEnough && farEnough)) {
      return;
    }

    try {
      const res = await oaV2CheckAddress({
        addresses: [{
          latitude: String(coords?.latitude || ''),
          longitude: String(coords?.longitude || '')
        }]
      });

      if (res.status === 0) {
        const addrText = res.data?.addressDetail;
        setLocation({
          ...coords,
          addressText: addrText
        });
        // 同步更新 actionCoords 的地址文本，确保当前需要打卡卡片显示最新地址
        try {
          setActionCoords({ latitude: coords?.latitude, longitude: coords?.longitude, addressText: addrText });
        } catch (_) {}
        lastAddressUpdateRef.current = { t: now, coords };
        // 成功则清除失败冷却
        addressErrorCooldownUntilRef.current = 0;
      } else {
        // 非成功状态视为失败，进入冷却
        addressErrorCooldownUntilRef.current = now + ADDRESS_ERROR_COOLDOWN_MS;
      }
    } catch (error) {
      // 吞错（不影响主流程），并进入冷却窗口
      if (typeof __DEV__ !== 'undefined' && __DEV__) {
        console.warn('[useClockIn] 获取地址失败:', error?.message || error);
      }
      addressErrorCooldownUntilRef.current = now + ADDRESS_ERROR_COOLDOWN_MS;
    }
  }, [setLocation, computeDistanceMeters]);

  /**
   * 生成打卡列表数据
   * @param {Object} actionTypeData 打卡类型数据
   * @param {Object} workingTimeInfoData 班次配置数据
   * @param {Object} checkInRecord 打卡记录数据
   * @returns {Array} 打卡列表
   */
  const generateClockInList = useCallback((actionTypeData, workingTimeInfoData, checkInRecord) => {
  
    const { isWorkDay, workTime, actionType: currentActionType } = actionTypeData || {};
    const records = checkInRecord?.records || [];
    
    // 生成基础工作时间列表
    const createWorkingTimesList = () => ((workingTimeInfoData?.Time ?? []).flatMap(timeSlot => ([
      { workTime: timeSlot?.OnWorkTime, actionTime: '', actionType: '', onOff: 'on' },
      { workTime: timeSlot?.OffWorkTime, actionTime: '', actionType: '', onOff: 'off' },
    ])));
    
    // 查找对应的打卡记录
    const findRecord = (targetWorkTime) => records.find(r => r.workTime === targetWorkTime);
    
    // 判断是否错过打卡时间（以分钟为精度）；缺少 workTime 时不视为错过
    const hhmmToMinutes = (str) => {
      const m = /^([0-9]{2}):([0-9]{2})$/.exec(str || '');
      if (!m) return NaN;
      return parseInt(m[1], 10) * 60 + parseInt(m[2], 10);
    };
    const isMissedTime = (targetWorkTime) => {
      const a = hhmmToMinutes(targetWorkTime);
      const b = hhmmToMinutes(workTime);
      if (Number.isNaN(a) || Number.isNaN(b)) return false;
      return a < b;
    };
    
    // 休息日处理 (isWorkDay === 2)
    if (isWorkDay === 2) {
      if (!records.length) {
        return [{
          workTime: 'rest_0',
          actionType: currentActionType || '',
          actionTime: '',
          onOff: 'on',
          clockActionType: '',
          isClockCard: true,
        }];
      }
      
      const [checkedOn = {}, checkedOff = {}] = records;

      return [
        {
          workTime: 'rest_0',
          actionTime: checkedOn.actionTime || '',
          actionType: '',
          checkAddress: checkedOn.checkAddress,
          onOff: 'on',
          clockActionType: checkedOn.actionType || '',
          isClockCard: false,
        },
        {
          workTime: 'rest_1',
          actionTime: checkedOff.actionTime || '',
          actionType: currentActionType || '',
          onOff: 'off',
          clockActionType: checkedOff.actionType || '',
          isClockCard: true,
        }
      ];
    }
    
    // 工作日/非工作日 (isWorkDay === 0 或 1)
    const workingTimes = createWorkingTimesList();
    const isWorkingDay = isWorkDay === 1;
   
    return workingTimes.map(timeSlot => {
      const record = findRecord(timeSlot.workTime);
      // 有记录优先合并记录字段，保证渲染所需信息完整
      const baseItem = record ? { ...timeSlot, ...record } : timeSlot;
      
      // 非工作日：仅展示基础信息，不允许打卡
      if (!isWorkingDay) {
        return {
          ...baseItem,
          clockActionType: '',
          isClockCard: false,
          actionType: '',
        };
      }
      
      const isCurrentTimeSlot = timeSlot.workTime === workTime;
      
      // 仅在没有 actionTime 且非当前卡点时，按时间窗判断 miss；
      // 有 actionTime 时以记录的 actionType 作为结果态展示
      const computedClockActionType = (() => {
        const hasActionTime = Boolean(record?.actionTime);
        if (hasActionTime) return record.actionType;
        if (!isCurrentTimeSlot && isMissedTime(timeSlot.workTime)) return 'miss';
        return '';
      })();
      
      return {
        ...baseItem,
        clockActionType: computedClockActionType,
        isClockCard: isCurrentTimeSlot,
        actionType: isCurrentTimeSlot ? (currentActionType || '') : '',
      };
    });
  }, []);

  // 校验列表可显示性
  const hasDisplayableCard = (list) => Array.isArray(list) && list.length > 0 && list.some(item => item && (typeof item.workTime === 'string' || typeof item.onOff === 'string'));

  /**
   * 基于位置信息更新打卡列表数据（带并发合并与等值判断）
   * @param {Object} coords 位置坐标信息
   * @param {Object} options 选项
   */
  const updateClockInListWithLocation = useCallback(async (coords, options = {}) => {
  
    // 合并并发：如果已有在途请求，直接复用其 Promise
    if (updateInFlightRef.current) {
      return updateInFlightRef.current;
    }

    const { silent = false } = options || {};
    const task = (async () => {
      try {
        // 验证位置信息有效性
        if (!coords || !coords.latitude || !coords.longitude) {
          console.warn('[useClockIn] 位置信息无效，跳过更新:', coords);
          return [];
        }
        
        if (!silent) {
          setLoading(true);
        }
        
        // 并行请求三个接口
        const actionTypePromise = getActionType(coords);
        const workingTimePromise = getWorkingTimeInfo();
        const collectionPromise = getCollectionDate();

        // 读取已缓存的 workingTimeResult（用于后续加载时的快速合成）
        const prevState = useClockInStore.getState();
        const cachedWorkingTime = prevState.workingTimeResult;
        const hasCachedWorkingTime = cachedWorkingTime != null;

        let nextActionType;
        let nextCollection;
        let nextWorkingTime;
        let nextList = [];

        if (!hasCachedWorkingTime) {
          // 初次加载：等待三个接口全部返回
          [nextActionType, nextWorkingTime, nextCollection] = await Promise.all([
            actionTypePromise,
            workingTimePromise,
            collectionPromise,
          ]);
          // 仅在有变化时写入 store
          if (JSON.stringify(prevState.actionTypeResult) !== JSON.stringify(nextActionType)) {
            setActionTypeResult(nextActionType);
            updateActionSnapshot(coords);
          }
          if (JSON.stringify(prevState.workingTimeResult) !== JSON.stringify(nextWorkingTime)) {
            setWorkingTimeResult(nextWorkingTime);
          }
          if (JSON.stringify(prevState.collectionResult) !== JSON.stringify(nextCollection)) {
            setCollectionResult(nextCollection);
          }

          // 地址文本解析做独立节流
          await getTextAddress(coords);

          // 基于获取的数据生成打卡列表
          nextList = generateClockInList(nextActionType, nextWorkingTime, nextCollection);
          if (hasDisplayableCard(nextList) && JSON.stringify(prevState.clockInList) !== JSON.stringify(nextList)) {
            setClockInList(nextList);
          }
        } else {
          // 后续加载：优先等待另外两个接口（actionType、collection），使用缓存的 workingTime 合成列表
          [nextActionType, nextCollection] = await Promise.all([
            actionTypePromise,
            collectionPromise,
          ]);

          // 仅在有变化时写入 store（workingTime 暂用缓存值）
          if (JSON.stringify(prevState.actionTypeResult) !== JSON.stringify(nextActionType)) {
            setActionTypeResult(nextActionType);
            updateActionSnapshot(coords);
          }
          if (JSON.stringify(prevState.collectionResult) !== JSON.stringify(nextCollection)) {
            setCollectionResult(nextCollection);
          }

          // 地址文本解析做独立节流
          await getTextAddress(coords);
          // 使用缓存的 workingTime 生成打卡列表（快速响应 UI）
          nextList = generateClockInList(nextActionType, cachedWorkingTime, nextCollection);
          if (hasDisplayableCard(nextList) && JSON.stringify(prevState.clockInList) !== JSON.stringify(nextList)) {
            setClockInList(nextList);
          }

          // 后台继续等待 workingTime 返回，并与缓存对比，若有变化则更新存储并二次刷新列表（不影响骨架屏）
          workingTimePromise
            .then((wt) => {
              try {
                const currentWT = useClockInStore.getState()?.workingTimeResult;
                if (JSON.stringify(currentWT) !== JSON.stringify(wt)) {
                  setWorkingTimeResult(wt);
                  const latestAction = useClockInStore.getState()?.actionTypeResult || nextActionType;
                  const latestCollection = useClockInStore.getState()?.collectionResult || nextCollection;
                  const updatedList = generateClockInList(latestAction, wt, latestCollection);
                  const currentList = useClockInStore.getState()?.clockInList;
                  if (hasDisplayableCard(updatedList) && JSON.stringify(currentList) !== JSON.stringify(updatedList)) {
                    setClockInList(updatedList);
                  }
                }
              } catch (e) {
                // ignore update failures
              }
            })
            .catch(() => {});
        }

        return nextList;
      } catch (error) {
        console.error('[useClockIn] 更新打卡列表失败:', error);
        if (!silent) {
          throw error;
        }
        return [];
      } finally {
        if (!silent) setLoading(false);
      }
    })();

    updateInFlightRef.current = task;
    task.finally(() => {
      updateInFlightRef.current = null;
    });

    return task;
  }, [getActionType, getWorkingTimeInfo, getCollectionDate, getTextAddress, generateClockInList, setActionTypeResult, setWorkingTimeResult, setCollectionResult, setClockInList, setLoading]);

  /**
   * 获取完整的打卡列表数据
   * 完全依赖位置监听获得的位置信息来更新打卡列表
   * 如果没有位置信息，返回空列表并提示启动位置监听
   */
  const getClockInList = useCallback(async (options = {}) => {
    try {
      // 优先使用位置监听的最新坐标，若暂无则回退使用 store 中的 location
      const currentLoc = useClockInStore.getState().location;
      const coords = lastLocationRef.current || currentLoc;
      
      if (coords) {
        return await updateClockInListWithLocation(coords, options);
      } else {
        console.warn('[useClockIn] 没有位置信息，请确保位置监听已启动');
        return [];
      }
    } catch (error) {
      console.error('[useClockIn] 获取打卡列表失败:', error);
      return [];
    }
  }, [updateClockInListWithLocation]);
  


  /**
   * 获取打卡按钮显示文字
   * @param {Object} record - 打卡记录数据
   * @param {Object} actionTypeData - 打卡类型数据
   * @returns {string} 按钮显示文字
   */
  const getBtnLabel = useCallback((record, actionTypeData) => {
    if (record.actionType === 'noClock') {
      if (record.onOff === 'on') {
        return t('btnText.workStartClockIn')
      } else {
        if (record.onOff === 'off' && record.isClockCard && record.clockActionType !== '') {
          return t('btnText.updateClockIn')
        }
        return t('btnText.workEndClockIn')
      }
    }
    if (actionTypeData.isWorkDay === 1) {
      if (record.actionType !== '' && record.actionType !== 'common') {
        return t(cardTypes[actionTypeData.actionType]?.clockBtnLabel);
      }
      if (record.onOff === 'on') {
        return t('btnText.workStartClockIn');
      } else if (record.onOff === 'off' && record.isClockCard && record.clockActionType !== '') {
        return t('btnText.updateClockIn');
      }
      else if (record.onOff === 'off' && record.actionTime === '') {
        return t('btnText.workEndClockIn');
      }
    } else {
      const isOutWork = typeof record?.actionType === 'string' && record.actionType.includes('outWork');
      if (record.onOff === 'on') {
        if (isOutWork) {
          return t('btnText.fieldClockIn');
        }
        return t('btnText.workStartClockIn');
      } else if (record.onOff === 'off') {
        if (isOutWork) {
          return t('btnText.fieldClockIn');
        }
        if (record.isClockCard && record.clockActionType !== '') {
          return t('btnText.updateClockIn');
        }
        return t('btnText.workEndClockIn');
      }
    }
  }, [t]);

  // 抽取：根据工作日/打卡记录决定设置的 clockType
  const applyClockTypeAfterClockIn = useCallback((serverClockType) => {
        
    try {
  const { setClockType } = useClockInStore.getState();
         setClockType(serverClockType);
    } catch (e) {
    
      console.warn('[useClockIn] applyClockTypeAfterClockIn error:', e);
    }
  }, []);

  /**
   * 开始位置监听
   * @param {Function} onLocationUpdate 位置更新回调
   */
  const startLocationWatching = useCallback(async (onLocationUpdate) => {
    try {
      
      setIsLocationWatching(true);
      
      locationUpdateCallbackRef.current = onLocationUpdate;
     
      await startWatchingLocation(
        (location) => {
          try {
            const coords = location.coords;
            const prevCoords = lastLocationRef.current;
            lastLocationRef.current = coords;
            
            const now = Date.now();
            const dt = now - lastUpdateTimestampRef.current;
            const dist = computeDistanceMeters(prevCoords, coords);
            const force = !!forceNextUpdateRef.current;
            const shouldUpdate = force || dt >= MIN_UPDATE_INTERVAL_MS || dist >= MIN_DISTANCE_CHANGE_M;

            if (!shouldUpdate) {
            } else {
              if (updateInFlightRef.current) {
                pendingCoordsRef.current = coords;
              } else {
                const p = updateClockInListWithLocation(coords, { silent: !force });
                updateInFlightRef.current = p;
                p.finally(() => {
                  lastUpdateTimestampRef.current = Date.now();
                  updateInFlightRef.current = null;
                  if (force) {
                    forceNextUpdateRef.current = false;
                    if (forcedUpdateTimeoutRef.current) {
                      clearTimeout(forcedUpdateTimeoutRef.current);
                      forcedUpdateTimeoutRef.current = null;
                    }
                    const resolver = forcedUpdateResolverRef.current;
                    forcedUpdateResolverRef.current = null;
                    if (resolver) resolver();
                  }
                  if (pendingCoordsRef.current) {
                    const next = pendingCoordsRef.current;
                    pendingCoordsRef.current = null;
                    const dt2 = Date.now() - lastUpdateTimestampRef.current;
                    const dist2 = computeDistanceMeters(lastLocationRef.current, next);
                    const force2 = !!forceNextUpdateRef.current;
                    if (dt2 >= MIN_UPDATE_INTERVAL_MS || dist2 >= MIN_DISTANCE_CHANGE_M || force2) {
                      const p2 = updateClockInListWithLocation(next, { silent: !force2 });
                      updateInFlightRef.current = p2;
                      p2.finally(() => {
                        lastUpdateTimestampRef.current = Date.now();
                        updateInFlightRef.current = null;
                        if (force2) {
                          forceNextUpdateRef.current = false;
                          if (forcedUpdateTimeoutRef.current) {
                            clearTimeout(forcedUpdateTimeoutRef.current);
                            forcedUpdateTimeoutRef.current = null;
                          }
                          const resolver2 = forcedUpdateResolverRef.current;
                          forcedUpdateResolverRef.current = null;
                          if (resolver2) resolver2();
                        }
                      });
                    }
                  }
                });
              }
            }

            if (locationUpdateCallbackRef.current) {
              locationUpdateCallbackRef.current(location);
            }
          } catch (callbackError) {
            console.error('[useClockIn] 位置更新回调处理失败:', callbackError);
          }
        },
        undefined,
        'REALTIME_TRACKING'
      );

    } catch (error) {
      console.error('[useClockIn] 启动位置监听失败:', error);
      setIsLocationWatching(false);
      locationUpdateCallbackRef.current = null;
      throw error;
    }
  }, [startWatchingLocation, updateClockInListWithLocation, computeDistanceMeters]);
  
  const stopLocationWatching = useCallback(async () => {
    try {
      await stopWatchingLocation();
      setIsLocationWatching(false);
      locationUpdateCallbackRef.current = null;
      updateInFlightRef.current = null;
      pendingCoordsRef.current = null;
    } catch (error) {
      console.error('[useClockIn] 停止位置监听失败:', error);
      setIsLocationWatching(false);
      locationUpdateCallbackRef.current = null;
      updateInFlightRef.current = null;
      pendingCoordsRef.current = null;
    }
  }, [stopWatchingLocation]);
  
  const restartWatchingAndRefresh = useCallback(async (ensureReadyFn) => {
    await stopLocationWatching();
    if (ensureReadyFn) {
      const ready = await ensureReadyFn();
      if (!ready) return; 
    }
    return new Promise(async (resolve, reject) => {
      try {
        // 清理已有的强制刷新定时器
        if (forcedUpdateTimeoutRef.current) {
          clearTimeout(forcedUpdateTimeoutRef.current);
          forcedUpdateTimeoutRef.current = null;
        }
        forcedUpdateResolverRef.current = resolve;
        forceNextUpdateRef.current = true;
        await startLocationWatching();
        // 启动强制刷新超时兜底，防止Promise悬挂
        forcedUpdateTimeoutRef.current = setTimeout(() => {
          if (forcedUpdateResolverRef.current) {
            const r = forcedUpdateResolverRef.current;
            forcedUpdateResolverRef.current = null;
            forceNextUpdateRef.current = false;
            try { r && r(); } catch (_) {}
          }
          forcedUpdateTimeoutRef.current = null;
        }, 8000);
      } catch (e) {
        forceNextUpdateRef.current = false;
        if (forcedUpdateTimeoutRef.current) {
          clearTimeout(forcedUpdateTimeoutRef.current);
          forcedUpdateTimeoutRef.current = null;
        }
        forcedUpdateResolverRef.current = null;
        console.error('[useClockIn] restartWatchingAndRefresh failed to start watch:', e);
        reject(e);
      }
    });
  }, [stopLocationWatching, startLocationWatching]);
  
  /**
   * 获取最后一次的位置信息
   */
  const getLastLocation = useCallback(() => {
    return lastLocationRef.current;
  }, []);

  return {
    // 状态
    loading,
    clockInList,
    clockInBtnLoading,
    setClockInBtnLoading,
    isLocationWatching,
    // 核心方法
    getClockInList,
    startLocationWatching,
    stopLocationWatching,
    getLastLocation,
    restartWatchingAndRefresh,
    // 辅助方法
    generateClockInList,
    getBtnLabel,
    applyClockTypeAfterClockIn,
  };
};