import { createCheckin, fetchCheckinsInRange, fetchDailyCheckins, syncCheckin as syncCheckinApi, updateCheckin } from '@/services/checkins';
import { createAction, createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';

export type CheckinExercise = {
  key: string;
  name: string;
  category: string;
  /**
   * itemType
   * - exercise: 正常训练动作（默认）
   * - rest: 组间/动作间休息（仅展示，不可勾选完成）
   * - note: 备注/口令提示（仅展示）
   */
  itemType?: 'exercise' | 'rest' | 'note';
  sets: number; // 组数（rest/note 可为 0）
  reps?: number; // 每组重复（计次型）
  durationSec?: number; // 每组时长（计时型）
  restSec?: number; // 休息时长（当 itemType=rest 时使用）
  note?: string; // 备注内容（当 itemType=note 时使用）
  completed?: boolean; // 是否已完成该动作
};

export type CheckinRecord = {
  id: string;
  date: string; // YYYY-MM-DD
  items: CheckinExercise[];
  note?: string;
  // 保留后端原始返回，便于当 metrics.items 为空时做回退展示
  raw?: any[];
};

export type CheckinState = {
  byDate: Record<string, CheckinRecord>;
  currentDate: string | null;
  monthLoaded: Record<string, boolean>; // key: YYYY-MM, 标记该月数据是否已加载
  pendingSyncDates?: string[]; // 待同步的日期列表
};

const initialState: CheckinState = {
  byDate: {},
  currentDate: null,
  monthLoaded: {},
};

function areItemsEqual(a: CheckinExercise[] | undefined, b: CheckinExercise[] | undefined): boolean {
  if (!a && !b) return true;
  if (!a || !b) return false;
  if (a.length !== b.length) return false;
  for (let i = 0; i < a.length; i++) {
    const ai = a[i];
    const bi = b[i];
    if (!ai || !bi) return false;
    // 逐字段对比，避免 JSON 序列化引入顺序差异
    if (
      ai.key !== bi.key ||
      ai.name !== bi.name ||
      ai.category !== bi.category ||
      (ai.itemType ?? 'exercise') !== (bi.itemType ?? 'exercise') ||
      ai.sets !== bi.sets ||
      ai.reps !== bi.reps ||
      ai.durationSec !== bi.durationSec ||
      ai.restSec !== bi.restSec ||
      ai.note !== bi.note ||
      (!!ai.completed) !== (!!bi.completed)
    ) {
      return false;
    }
  }
  return true;
}

function ensureRecord(state: CheckinState, date: string): CheckinRecord {
  if (!state.byDate[date]) {
    state.byDate[date] = {
      id: `rec_${date}`,
      date,
      items: [],
    };
  }
  return state.byDate[date];
}

// 内部 action，用于标记需要同步的日期
export const triggerAutoSync = createAction<{ date: string }>('checkin/triggerAutoSync');

const checkinSlice = createSlice({
  name: 'checkin',
  initialState,
  reducers: {
    setCurrentDate(state, action: PayloadAction<string>) {
      state.currentDate = action.payload; // 期望格式 YYYY-MM-DD
      ensureRecord(state, action.payload);
    },
    addExercise(state, action: PayloadAction<{ date: string; item: CheckinExercise }>) {
      const rec = ensureRecord(state, action.payload.date);
      // 若同 key 已存在则覆盖参数（更接近用户"重新选择/编辑"的心智）
      const idx = rec.items.findIndex((it) => it.key === action.payload.item.key);
      const normalized: CheckinExercise = { ...action.payload.item, completed: false };
      if (idx >= 0) rec.items[idx] = normalized; else rec.items.push(normalized);
      // 标记需要同步
      state.pendingSyncDates = state.pendingSyncDates || [];
      if (!state.pendingSyncDates.includes(action.payload.date)) {
        state.pendingSyncDates.push(action.payload.date);
      }
    },
    removeExercise(state, action: PayloadAction<{ date: string; key: string }>) {
      const rec = ensureRecord(state, action.payload.date);
      rec.items = rec.items.filter((it) => it.key !== action.payload.key);
      // 标记需要同步
      state.pendingSyncDates = state.pendingSyncDates || [];
      if (!state.pendingSyncDates.includes(action.payload.date)) {
        state.pendingSyncDates.push(action.payload.date);
      }
    },
    replaceExercises(state, action: PayloadAction<{ date: string; items: CheckinExercise[]; note?: string }>) {
      const rec = ensureRecord(state, action.payload.date);
      rec.items = (action.payload.items || []).map((it) => ({ ...it, completed: false }));
      if (typeof action.payload.note === 'string') rec.note = action.payload.note;
      // 标记需要同步
      state.pendingSyncDates = state.pendingSyncDates || [];
      if (!state.pendingSyncDates.includes(action.payload.date)) {
        state.pendingSyncDates.push(action.payload.date);
      }
    },
    toggleExerciseCompleted(state, action: PayloadAction<{ date: string; key: string }>) {
      const rec = ensureRecord(state, action.payload.date);
      const idx = rec.items.findIndex((it) => it.key === action.payload.key);
      if (idx >= 0 && (rec.items[idx].itemType ?? 'exercise') === 'exercise') {
        rec.items[idx].completed = !rec.items[idx].completed;
        // 标记需要同步
        state.pendingSyncDates = state.pendingSyncDates || [];
        if (!state.pendingSyncDates.includes(action.payload.date)) {
          state.pendingSyncDates.push(action.payload.date);
        }
      }
    },
    setNote(state, action: PayloadAction<{ date: string; note: string }>) {
      const rec = ensureRecord(state, action.payload.date);
      rec.note = action.payload.note;
      // 标记需要同步
      state.pendingSyncDates = state.pendingSyncDates || [];
      if (!state.pendingSyncDates.includes(action.payload.date)) {
        state.pendingSyncDates.push(action.payload.date);
      }
    },
    resetDate(state, action: PayloadAction<string>) {
      delete state.byDate[action.payload];
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(syncCheckin.fulfilled, (state, action) => {
        if (!action.payload) return;
        const { date, items, note, id } = action.payload;
        const prev = state.byDate[date];
        const nextId = id || prev?.id || `rec_${date}`;
        const nextItems = items || [];
        const isSame = prev && prev.id === nextId && prev.note === note && areItemsEqual(prev.items, nextItems);
        if (isSame) return;
        state.byDate[date] = { id: nextId, date, items: nextItems, note };
      })
      .addCase(autoSyncCheckin.fulfilled, (state, action) => {
        if (!action.payload) return;
        const { date, items, note, id } = action.payload;
        const prev = state.byDate[date];
        if (prev) {
          // 更新 ID（如果服务器返回了新的 ID）
          if (id && id !== prev.id) {
            state.byDate[date] = { ...prev, id };
          }
        }
        // 清除同步标记
        if (state.pendingSyncDates) {
          state.pendingSyncDates = state.pendingSyncDates.filter(d => d !== date);
        }
      })
      .addCase(getDailyCheckins.fulfilled, (state, action) => {
        const date = action.payload.date as string | undefined;
        const list = action.payload.list || [];
        if (!date) return;
        let mergedItems: CheckinExercise[] = [];
        let note: string | undefined = undefined;
        let id: string | undefined = state.byDate[date]?.id;
        for (const rec of list) {
          if (!rec) continue;
          if (rec.id && !id) id = String(rec.id);
          const itemsFromMetrics = rec?.metrics?.items ?? rec?.items;
          if (Array.isArray(itemsFromMetrics)) {
            mergedItems = itemsFromMetrics as CheckinExercise[];
          }
          if (typeof rec.notes === 'string') note = rec.notes as string;
        }
        const prev = state.byDate[date];
        const nextId = id || prev?.id || `rec_${date}`;
        const shouldUseRaw = (mergedItems?.length ?? 0) === 0;
        const isSameMain = prev && prev.id === nextId && prev.note === note && areItemsEqual(prev.items, mergedItems);
        if (isSameMain) {
          // 若本地已有 items，则无需更新 raw 以免触发无效渲染
          if (!shouldUseRaw) return;
          // 若仅用于展示原始记录（本地 items 为空），允许更新 raw
          state.byDate[date] = { ...prev, raw: list } as CheckinRecord;
          return;
        }
        state.byDate[date] = { id: nextId, date, items: mergedItems, note, raw: shouldUseRaw ? list : prev?.raw };
      })
      .addCase(loadMonthCheckins.fulfilled, (state, action) => {
        const monthKey = action.payload.monthKey;
        const merged = action.payload.byDate;
        for (const d of Object.keys(merged)) {
          const prev = state.byDate[d];
          const next = merged[d];
          const items = (next.items && next.items.length > 0) ? next.items : (prev?.items ?? []);
          const note = (typeof next.note === 'string') ? next.note : prev?.note;
          const id = next.id || prev?.id || `rec_${d}`;
          const raw = prev?.raw ?? (next as any)?.raw;
          state.byDate[d] = { id, date: d, items, note, raw } as CheckinRecord;
        }
        state.monthLoaded[monthKey] = true;
      });
  },
});

export const { setCurrentDate, addExercise, removeExercise, replaceExercises, toggleExerciseCompleted, setNote, resetDate } = checkinSlice.actions;
export default checkinSlice.reducer;

// Thunks
export const syncCheckin = createAsyncThunk('checkin/sync', async (record: { date: string; items: CheckinExercise[]; note?: string; id?: string }, { getState }) => {
  const state = getState() as any;
  const existingId: string | undefined = record.id || state?.checkin?.byDate?.[record.date]?.id;
  const metrics = { items: record.items } as any;
  if (!existingId || existingId.startsWith('rec_')) {
    const created = await createCheckin({
      title: '每日训练打卡',
      checkinDate: record.date,
      notes: record.note,
      metrics,
      startedAt: new Date().toISOString(),
    });
    const newId = (created as any)?.id;
    return { id: newId, date: record.date, items: record.items, note: record.note };
  }
  const updated = await updateCheckin({ id: existingId, notes: record.note, metrics });
  const newId = (updated as any)?.id ?? existingId;
  return { id: newId, date: record.date, items: record.items, note: record.note };
});

// 自动同步：当数据发生变动时自动调用
export const autoSyncCheckin = createAsyncThunk(
  'checkin/autoSync',
  async (payload: { date: string }, { getState, dispatch }) => {
    const state = getState() as any;
    const record = state?.checkin?.byDate?.[payload.date];
    if (!record) return null;
    
    // 只有当有实际数据时才同步
    if (!record.items || record.items.length === 0) return null;
    
    try {
      const result = await syncCheckinApi({
        date: payload.date,
        items: record.items,
        note: record.note,
        id: record.id,
      });
      return { 
        date: payload.date, 
        items: record.items, 
        note: record.note, 
        id: result.id || record.id 
      };
    } catch (error) {
      console.warn('自动同步失败:', error);
      // 不抛出错误，避免影响用户操作
      return null;
    }
  }
);

// 获取当天打卡列表（用于进入页面时拉取最新云端数据）
export const getDailyCheckins = createAsyncThunk('checkin/getDaily', async (date?: string) => {
  const dateParam = date ?? new Date().toISOString().slice(0, 10);
  const list = await fetchDailyCheckins(dateParam);
  try { console.log('getDailyCheckins', { date: dateParam, count: Array.isArray(list) ? list.length : -1 }); } catch { }
  return { date: dateParam, list } as { date?: string; list: any[] };
});

// 按月加载：优先使用区间接口，失败则逐日回退
export const loadMonthCheckins = createAsyncThunk(
  'checkin/loadMonth',
  async (payload: { year: number; month1Based: number }, { getState }) => {
    const { year, month1Based } = payload;
    const pad = (n: number) => `${n}`.padStart(2, '0');
    const monthKey = `${year}-${pad(month1Based)}`;

    const start = `${year}-${pad(month1Based)}-01`;
    const endDate = new Date(year, month1Based, 0).getDate();
    const end = `${year}-${pad(month1Based)}-${pad(endDate)}`;

    try {
      const list = await fetchCheckinsInRange(start, end);
      const byDate: Record<string, CheckinRecord> = {};
      for (const rec of list) {
        const date = rec?.checkinDate || rec?.date;
        if (!date) continue;
        const id = rec?.id ? String(rec.id) : `rec_${date}`;
        const items = (rec?.metrics?.items ?? rec?.items) ?? [];
        const note = typeof rec?.notes === 'string' ? rec.notes : undefined;
        byDate[date] = { id, date, items, note };
      }
      return { monthKey, byDate } as { monthKey: string; byDate: Record<string, CheckinRecord> };
    } catch {
      // 回退逐日请求（并行）
      const endNum = new Date(year, month1Based, 0).getDate();
      const dates = Array.from({ length: endNum }, (_, i) => `${year}-${pad(month1Based)}-${pad(i + 1)}`);
      const results = await Promise.all(
        dates.map(async (d) => ({ d, list: await fetchDailyCheckins(d) }))
      );
      const byDate: Record<string, CheckinRecord> = {};
      for (const { d, list } of results) {
        let items: CheckinExercise[] = [];
        let note: string | undefined;
        let id: string | undefined;
        for (const rec of list) {
          if (rec?.id && !id) id = String(rec.id);
          const metricsItems = rec?.metrics?.items ?? rec?.items;
          if (Array.isArray(metricsItems)) items = metricsItems as CheckinExercise[];
          if (typeof rec?.notes === 'string') note = rec.notes as string;
        }
        byDate[d] = { id: id || `rec_${d}`, date: d, items, note };
      }
      return { monthKey, byDate } as { monthKey: string; byDate: Record<string, CheckinRecord> };
    }
  },
  {
    condition: (payload, { getState }) => {
      const state = getState() as any;
      const pad = (n: number) => `${n}`.padStart(2, '0');
      const monthKey = `${payload.year}-${pad(payload.month1Based)}`;
      return !state?.checkin?.monthLoaded?.[monthKey];
    },
  }
);


