import { create } from 'zustand';
import dayjs from 'dayjs';
import { ServerTeamCollection } from '@/api/attendance';
import { createResettableStore } from '../registry';
import { useAuthStore } from '@/stores/auth';
import { useToast } from '@/utils/ui/toast';

// 轻量内存缓存与在途管理（不落盘）
const CACHE_TTL = 120 * 1000; // 120s
const CACHE_MAX = 5; // 每个模式最多5条

// 简易 LRU 缓存：Map 末尾为最近使用
function lruGet(cache, key) {
  if (!cache.has(key)) return null;
  const entry = cache.get(key);
  if (!entry) return null;
  if (Date.now() - entry.ts > CACHE_TTL) {
    cache.delete(key);
    return null;
  }
  // 触发 LRU：删除后再 set 到尾部
  cache.delete(key);
  cache.set(key, entry);
  return entry.data;
}
function lruSet(cache, key, data) {
  cache.set(key, { data, ts: Date.now() });
  if (cache.size > CACHE_MAX) {
    const firstKey = cache.keys().next().value;
    if (firstKey != null) cache.delete(firstKey);
  }
}

const dayCache = new Map();
const weekCache = new Map();
const monthCache = new Map();

// 团队静默刷新在途去重（不落盘）
const revalidatePendingMap = new Map();

// 稳定字符串化 + 短哈希，用于参与缓存键的“过滤参数摘要”
function getUserKey() {
  try {
    const u = useAuthStore.getState().getUser?.() || useAuthStore.getState().user;
    return u?.ID ? String(u.ID) : 'anon';
  } catch {
    return 'anon';
  }
}

// 统一空结果（不影响 UI 渲染）
const EMPTY_OBJ = {};
const EMPTY_ARR = [];

const createTeamAttendanceStore = () => create((set, get) => ({
  // 团队考勤统计模式: day-日统计, week-周统计, month-月统计
  activeStatisticsMode: 'day',
  // 周/月统计裁剪后的日期数组（用于统计详情展示）
  clippedDates: [],
  // 团队考勤权限标记
  inTeamAttendance: false,

  // 当前显示的数据 cacheKey（用于防止静默刷新的竞态覆盖）
  currentDisplayCacheKey: null,

  // 团队考勤全数据(日/周/月)
  teamCollection_day: {},
  teamStatisticsData_day: [],

  teamCollection_week: {},
  teamStatisticsData_week: [],

  teamCollection_month: {},
  teamStatisticsData_month: [],

  // 查看的指定考勤人员信息
  viewTeamMember: {},

  // 在途请求去重与取消、takeLatest 守卫
  pendingMap: new Map(), // key -> Promise
  dayLatestReqId: 0,
  weekLatestReqId: 0,
  monthLatestReqId: 0,
  dayAbortController: null,
  weekAbortController: null,
  monthAbortController: null,

  // 静默刷新"今天"数据的 takeLatest 守卫
  dayRevalidateReqId: 0,
  weekRevalidateReqId: 0,
  monthRevalidateReqId: 0,

  // 加载计数与上次成功更新时间
  loadingCount: 0,
  lastUpdateTime: null,

  // 静默刷新进行中计数（仅用于按钮禁用，不影响全局加载态）
  revalidatingCount: 0,

  // 增减 loading
  incLoading: () => set((s) => ({ loadingCount: (s.loadingCount || 0) + 1 })),
  decLoading: () => set((s) => ({ loadingCount: Math.max(0, (s.loadingCount || 0) - 1) })),
  setLastUpdateTime: (ts) => set({ lastUpdateTime: ts }),

  // 增加/减少 静默刷新计数，避免出现负数
  incRevalidating: () => set((s) => ({ revalidatingCount: (s.revalidatingCount || 0) + 1 })),
  decRevalidating: () => set((s) => ({ revalidatingCount: Math.max(0, (s.revalidatingCount || 0) - 1) })),

  // 设置统计模式
  setActiveStatisticsMode: (mode) => set({ activeStatisticsMode: mode }),
  // 设置周/月统计裁剪后的日期数组
  setClippedDates: (clippedDates) => set({ clippedDates }),
  // 设置团队考勤权限标记
  setInTeamAttendance: (flag) => set({ inTeamAttendance: !!flag }),
  // 设置全量数据/统计数据（保留原接口）
  setTeamCollection_day: (teamCollection_day) => set({ teamCollection_day }),
  setTeamCollection_week: (teamCollection_week) => set({ teamCollection_week }),
  setTeamCollection_month: (teamCollection_month) => set({ teamCollection_month }),
  setTeamStatisticsData_day: (teamStatisticsData_day) => set({ teamStatisticsData_day }),
  setTeamStatisticsData_week: (teamStatisticsData_week) => set({ teamStatisticsData_week }),
  setTeamStatisticsData_month: (teamStatisticsData_month) => set({ teamStatisticsData_month }),

  // 设置要查看的指定考勤人员信息
  setViewTeamMember: (viewTeamMember) => set({ viewTeamMember }),

  // ===== 内部工具：构建键与未来时间判定 =====
  _buildDayKeyAndFuture: (data) => {
    const isDay = data?.collectionType === 1;
    const dateStr = data?.date;
    if (!isDay || !dateStr) return { key: null, isFuture: false };
    const uid = getUserKey();
    const today = dayjs().startOf('day');
    const isFuture = dayjs(dateStr).isAfter(today, 'day');
    const key = `${uid}|day|${dateStr}`;
    return { key, isFuture, dateStr };
  },
  _buildWeekKeyAndFuture: (data) => {
    const isRange = data?.collectionType === 2;
    const dates = Array.isArray(data?.dates) ? data.dates : [];
    if (!isRange || dates.length === 0) return { key: null, isFuture: false };
    const uid = getUserKey();
    // 容错：不假设排序，取范围端点
    const startDate = dates.reduce((min, d) => (min && min < d ? min : d), null) || dates[0];
    const endDate = dates.reduce((max, d) => (max && max > d ? max : d), null) || dates[dates.length - 1];
    const today = dayjs().startOf('day');
    const isFuture = dayjs(startDate).isAfter(today, 'day'); // 所有 dates 均在未来时短路
    const key = `${uid}|week|${startDate}_${endDate}`;
    return { key, isFuture, startDate, endDate };
  },
  _buildMonthKeyAndFuture: (data) => {
    const isRange = data?.collectionType === 2;
    const dates = Array.isArray(data?.dates) ? data.dates : [];
    if (!isRange || dates.length === 0) return { key: null, isFuture: false };
    const uid = getUserKey();
    const startDate = dates.reduce((min, d) => (min && min < d ? min : d), null) || dates[0];
    const endDate = dates.reduce((max, d) => (max && max > d ? max : d), null) || dates[dates.length - 1];
    const today = dayjs().startOf('day');
    const isFuture = dayjs(startDate).isAfter(today, 'day');
    const key = `${uid}|month|${startDate}_${endDate}`;
    return { key, isFuture, startDate, endDate };
  },

  // ===== 内部工具：静默刷新相关 =====
  // 判断查询的数据是否包含今天
  _containsToday: (data, mode) => {
    const today = dayjs().format('YYYY-MM-DD');
    if (mode === 'day') {
      const d = data?.date;
      return d === today;
    } else if (mode === 'week' || mode === 'month') {
      const dates = Array.isArray(data?.dates) ? data.dates : [];
      return dates.includes(today);
    }
    return false;
  },

  // 深度比较数据是否相同
  _isDataEqual: (data1, data2) => {
    try {
      return JSON.stringify(data1) === JSON.stringify(data2);
    } catch {
      return false;
    }
  },

  // 静默刷新包含"今天"的数据（无阈值，立即刷新）
  _refreshTodayData: async (cacheKey, data, mode, originalOptions = {}) => {
    const refreshKey = `${mode}:${cacheKey}`;
    if (!cacheKey) return;
    if (revalidatePendingMap.has(refreshKey)) return;

    // 根据模式选择合适的刷新ID
    const revalidateReqId = (get()[`${mode}RevalidateReqId`] || 0) + 1;
    set({ [`${mode}RevalidateReqId`]: revalidateReqId });

    // 进入静默刷新进行中计数（仅用于按钮禁用）
    get().incRevalidating();

    // 准备请求数据：周/月裁剪未来日期
    let payload = { ...data };
    if (mode === 'week' || mode === 'month') {
      const origDates = Array.isArray(data?.dates) ? data.dates : [];
      const today = dayjs().startOf('day');
      const clippedDates = origDates.filter((d) => !dayjs(d).isAfter(today, 'day'));
      payload = { ...payload, dates: clippedDates.length ? clippedDates : origDates };
    }

    // 选择对应模式的缓存
    let cache;
    if (mode === 'day') cache = dayCache;
    else if (mode === 'week') cache = weekCache;
    else cache = monthCache;

    const promise = ServerTeamCollection(payload, { ...originalOptions, signal: undefined })
      .then((res) => {
        // 仅最新静默请求可写入，旧请求结果直接丢弃
        if (revalidateReqId !== get()[`${mode}RevalidateReqId`]) {
          return;
        }
        if (res && res.status === 0) {
          const newData = res?.data ?? {};
          const cachedData = lruGet(cache, cacheKey);
          // 数据变化才更新
          if (!get()._isDataEqual(cachedData, newData)) {
            // 更新缓存
            lruSet(cache, cacheKey, newData);

            // 更新UI（检查模式匹配 && cacheKey匹配）
            const currentMode = get().activeStatisticsMode;
            const currentKey = get().currentDisplayCacheKey;
            if (currentMode === mode && currentKey === cacheKey) {
              if (mode === 'day') {
                set({ teamCollection_day: newData, teamStatisticsData_day: newData, lastUpdateTime: Date.now() });
              } else if (mode === 'week') {
                set({ teamCollection_week: newData, teamStatisticsData_week: newData, lastUpdateTime: Date.now() });
              } else {
                set({ teamCollection_month: newData, teamStatisticsData_month: newData, lastUpdateTime: Date.now() });
              }
            }
          }
        }
        // 静默请求失败或被取消，不做提示
      })
      .catch(() => {
        // 静默失败，不影响用户
      })
      .finally(() => {
        revalidatePendingMap.delete(refreshKey);
        // 退出静默刷新进行中计数
        get().decRevalidating();
      });

    revalidatePendingMap.set(refreshKey, promise);
  },

  // ===== 日模式 =====
  fetchTeamAttendanceDay: async (data = {}, options = {}) => {
    const { key, isFuture } = get()._buildDayKeyAndFuture(data);
    if (!key) return { status: -1, error: new Error('参数缺失: date') };

    // 未来短路：不请求、不缓存
    if (isFuture) {
      set({ teamCollection_day: EMPTY_OBJ, teamStatisticsData_day: EMPTY_ARR });
      return { status: 0, data: EMPTY_OBJ, shortCircuited: true };
    }

    // 缓存命中
    const cached = lruGet(dayCache, key);
    if (cached) {
      const prev = get().teamCollection_day;
      if (prev !== cached) {
        set({ teamCollection_day: cached, teamStatisticsData_day: cached, currentDisplayCacheKey: key });
      } else {
        set({ currentDisplayCacheKey: key });
      }
      // 检测是否包含今天，若包含则静默刷新（无阈值）
      if (get()._containsToday(data, 'day')) {
        get()._refreshTodayData(key, data, 'day', options);
      }
      return { status: 0, data: cached, cache: true };
    }

    // 在途去重
    const pendingMap = get().pendingMap;
    if (pendingMap.has(key)) return await pendingMap.get(key);

    // 进入加载态 + takeLatest + 取消控制
    get().incLoading();
    const reqId = (get().dayLatestReqId || 0) + 1;
    set({ dayLatestReqId: reqId });

    let { signal } = options || {};
    let usedStoreController = false;
    if (!signal && typeof AbortController !== 'undefined') {
      const prevController = get().dayAbortController;
      if (prevController) {
        try { prevController.abort(); } catch {}
      }
      const controller = new AbortController();
      set({ dayAbortController: controller });
      signal = controller.signal;
      usedStoreController = true;
    }

    const payload = { ...data };

    const promise = ServerTeamCollection(payload, { ...(options || {}), ...(signal ? { signal } : {}) })
      .then((res) => {
        if (reqId !== get().dayLatestReqId) return res; // 过时
        if (res && res.status === 0) {
          const result = res?.data ?? EMPTY_OBJ;
          // 最小落盘：不复制大对象
          set({ teamCollection_day: result, teamStatisticsData_day: result, lastUpdateTime: Date.now(), currentDisplayCacheKey: key });
          lruSet(dayCache, key, result);
        } else if (res && res.canceled) {
          // 取消静默
        } else {
          useToast.showError(res?.msg || res?.err || res?.error || '请求失败');
        }
        return res;
      })
      .catch((err) => {
        if (reqId !== get().dayLatestReqId) return { status: -999, canceled: true };
        const msg = err?.message || err?.msg || '';
        const code = err?.code || '';
        if (code === 'ERR_CANCELED' || /cancel|取消/i.test(msg)) return { status: -999, canceled: true };
        useToast.showError(msg || '网络或服务异常');
        return { status: -1, error: err };
      })
      .finally(() => {
        pendingMap.delete(key);
        if (usedStoreController && reqId === get().dayLatestReqId) set({ dayAbortController: null });
        get().decLoading();
      });

    pendingMap.set(key, promise);
    return await promise;
  },

  // ===== 周模式 =====
  fetchTeamAttendanceWeek: async (data = {}, options = {}) => {
    const today = dayjs().startOf('day');
    const origDates = Array.isArray(data?.dates) ? data.dates : [];
    const clippedDates = origDates.filter((d) => !dayjs(d).isAfter(today, 'day'));
    get().setClippedDates(clippedDates)
    const { key: origKey, isFuture } = get()._buildWeekKeyAndFuture(data);
    if (!origKey) return { status: -1, error: new Error('参数缺失: weekKey 或 (year, month, weekNo)/(startDate,endDate)') };
  
    if (isFuture || clippedDates.length === 0) {
      set({ teamCollection_week: EMPTY_OBJ, teamStatisticsData_week: EMPTY_ARR });
      return { status: 0, data: EMPTY_OBJ, shortCircuited: true };
    }
  
    const newData = { ...data, dates: clippedDates };
    const { key } = get()._buildWeekKeyAndFuture(newData);
  
    const cached = lruGet(weekCache, key);
    if (cached) {
      const prev = get().teamCollection_week;
      if (prev !== cached) {
        set({ teamCollection_week: cached, teamStatisticsData_week: cached, currentDisplayCacheKey: key });
      } else {
        set({ currentDisplayCacheKey: key });
      }
      if (get()._containsToday(newData, 'week')) {
        get()._refreshTodayData(key, newData, 'week', options);
      }
      return { status: 0, data: cached, cache: true };
    }
  
    const pendingMap = get().pendingMap;
    if (pendingMap.has(key)) return await pendingMap.get(key);
  
    get().incLoading();
    const reqId = (get().weekLatestReqId || 0) + 1;
    set({ weekLatestReqId: reqId });
  
    let { signal } = options || {};
    let usedStoreController = false;
    if (!signal && typeof AbortController !== 'undefined') {
      const prevController = get().weekAbortController;
      if (prevController) {
        try { prevController.abort(); } catch {}
      }
      const controller = new AbortController();
      set({ weekAbortController: controller });
      signal = controller.signal;
      usedStoreController = true;
    }
  
    const payload = { ...newData };
  
    const promise = ServerTeamCollection(payload, { ...(options || {}), ...(signal ? { signal } : {}) })
      .then((res) => {
        if (reqId !== get().weekLatestReqId) return res;
        if (res && res.status === 0) {
          const result = res?.data ?? EMPTY_OBJ;
          set({ teamCollection_week: result, teamStatisticsData_week: result, lastUpdateTime: Date.now(), currentDisplayCacheKey: key });
          lruSet(weekCache, key, result);
        } else if (res && res.canceled) {
          // ignore
        } else {
          useToast.showError(res?.msg || res?.err || res?.error || '请求失败');
        }
        return res;
      })
      .catch((err) => {
        if (reqId !== get().weekLatestReqId) return { status: -999, canceled: true };
        const msg = err?.message || err?.msg || '';
        const code = err?.code || '';
        if (code === 'ERR_CANCELED' || /cancel|取消/i.test(msg)) return { status: -999, canceled: true };
        useToast.showError(msg || '网络或服务异常');
        return { status: -1, error: err };
      })
      .finally(() => {
        pendingMap.delete(key);
        if (usedStoreController && reqId === get().weekLatestReqId) set({ weekAbortController: null });
        get().decLoading();
      });
  
    pendingMap.set(key, promise);
    return await promise;
  },

  // ===== 月模式 =====
  fetchTeamAttendanceMonth: async (data = {}, options = {}) => {
    const today = dayjs().startOf('day');
    const origDates = Array.isArray(data?.dates) ? data.dates : [];
    const clippedDates = origDates.filter((d) => !dayjs(d).isAfter(today, 'day'));
    get().setClippedDates(clippedDates)
    const { key: origKey, isFuture } = get()._buildMonthKeyAndFuture(data);
    if (!origKey) return { status: -1, error: new Error('参数缺失: month 或 (year, month)') };
  
    if (isFuture || clippedDates.length === 0) {
      set({ teamCollection_month: EMPTY_OBJ, teamStatisticsData_month: EMPTY_ARR });
      return { status: 0, data: EMPTY_OBJ, shortCircuited: true };
    }
  
    const newData = { ...data, dates: clippedDates };
    const { key } = get()._buildMonthKeyAndFuture(newData);
  
    const cached = lruGet(monthCache, key);
    if (cached) {
      const prev = get().teamCollection_month;
      if (prev !== cached) {
        set({ teamCollection_month: cached, teamStatisticsData_month: cached, currentDisplayCacheKey: key });
      } else {
        set({ currentDisplayCacheKey: key });
      }
      if (get()._containsToday(newData, 'month')) {
        get()._refreshTodayData(key, newData, 'month', options);
      }
      return { status: 0, data: cached, cache: true };
    }
  
    const pendingMap = get().pendingMap;
    if (pendingMap.has(key)) return await pendingMap.get(key);
  
    get().incLoading();
    const reqId = (get().monthLatestReqId || 0) + 1;
    set({ monthLatestReqId: reqId });
  
    let { signal } = options || {};
    let usedStoreController = false;
    if (!signal && typeof AbortController !== 'undefined') {
      const prevController = get().monthAbortController;
      if (prevController) {
        try { prevController.abort(); } catch {}
      }
      const controller = new AbortController();
      set({ monthAbortController: controller });
      signal = controller.signal;
      usedStoreController = true;
    }
  
    const payload = { ...newData };
  
    const promise = ServerTeamCollection(payload, { ...(options || {}), ...(signal ? { signal } : {}) })
      .then((res) => {
        if (reqId !== get().monthLatestReqId) return res;
        if (res && res.status === 0) {
          const result = res?.data ?? EMPTY_OBJ;
          set({ teamCollection_month: result, teamStatisticsData_month: result, lastUpdateTime: Date.now(), currentDisplayCacheKey: key });
          lruSet(monthCache, key, result);
        } else if (res && res.canceled) {
          // ignore
        } else {
          useToast.showError(res?.msg || res?.err || res?.error || '请求失败');
        }
        return res;
      })
      .catch((err) => {
        if (reqId !== get().monthLatestReqId) return { status: -999, canceled: true };
        const msg = err?.message || err?.msg || '';
        const code = err?.code || '';
        if (code === 'ERR_CANCELED' || /cancel|取消/i.test(msg)) return { status: -999, canceled: true };
        useToast.showError(msg || '网络或服务异常');
        return { status: -1, error: err };
      })
      .finally(() => {
        pendingMap.delete(key);
        if (usedStoreController && reqId === get().monthLatestReqId) set({ monthAbortController: null });
        get().decLoading();
      });
  
    pendingMap.set(key, promise);
    return await promise;
  },
}));

const resettableTeamAttendance = createResettableStore('teamAttendanceStore', createTeamAttendanceStore);
export const useTeamAttendanceStore = resettableTeamAttendance.useStore;