import { createSlice, createAsyncThunk, PayloadAction, createEntityAdapter } from '@reduxjs/toolkit';
import { RootState } from '../store';

// Define Activity type
export interface Activity {
  id: string;
  childId: string;
  type: 'feeding' | 'sleep' | 'diaper' | 'medication' | 'milestone' | 'note';
  timestamp: string;
  data: Record<string, any>;
  notes?: string;
  createdBy: string;
  createdAt: string;
  updatedAt: string;
  // Offline metadata
  _optimistic?: boolean;
  _localId?: string;
  _version?: number;
}

// Create entity adapter for normalized state
const activitiesAdapter = createEntityAdapter<Activity>({
  selectId: (activity) => activity.id,
  sortComparer: (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),
});

// Async thunks with offline support
export const createActivity = createAsyncThunk(
  'activities/create',
  async (activity: Omit<Activity, 'id' | 'createdAt' | 'updatedAt'>, { rejectWithValue }) => {
    try {
      const response = await fetch('/api/v1/activities', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(activity),
      });

      if (!response.ok) {
        throw new Error('Failed to create activity');
      }

      return await response.json();
    } catch (error: any) {
      return rejectWithValue(error.message);
    }
  }
);

export const fetchActivities = createAsyncThunk(
  'activities/fetch',
  async ({ childId, startDate, endDate }: { childId: string; startDate?: string; endDate?: string }) => {
    const params = new URLSearchParams({
      childId,
      ...(startDate && { startDate }),
      ...(endDate && { endDate }),
    });

    const response = await fetch(`/api/v1/activities?${params}`);
    if (!response.ok) {
      throw new Error('Failed to fetch activities');
    }

    const data = await response.json();
    return data.data;
  }
);

export const updateActivity = createAsyncThunk(
  'activities/update',
  async ({ id, updates }: { id: string; updates: Partial<Activity> }, { rejectWithValue }) => {
    try {
      const response = await fetch(`/api/v1/activities/${id}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updates),
      });

      if (!response.ok) {
        throw new Error('Failed to update activity');
      }

      return await response.json();
    } catch (error: any) {
      return rejectWithValue(error.message);
    }
  }
);

export const deleteActivity = createAsyncThunk(
  'activities/delete',
  async (id: string, { rejectWithValue }) => {
    try {
      const response = await fetch(`/api/v1/activities/${id}`, {
        method: 'DELETE',
      });

      if (!response.ok) {
        throw new Error('Failed to delete activity');
      }

      return id;
    } catch (error: any) {
      return rejectWithValue(error.message);
    }
  }
);

const activitiesSlice = createSlice({
  name: 'activities',
  initialState: activitiesAdapter.getInitialState({
    loading: false,
    error: null as string | null,
    syncStatus: 'idle' as 'idle' | 'syncing' | 'synced' | 'error',
    lastSyncTime: null as string | null,
  }),
  reducers: {
    // Optimistic create - immediately add to local state
    optimisticCreate: (state, action: PayloadAction<Activity>) => {
      const optimisticActivity = {
        ...action.payload,
        _optimistic: true,
        _localId: action.payload.id,
        _version: 1,
      };
      activitiesAdapter.addOne(state, optimisticActivity);
    },
    // Optimistic update
    optimisticUpdate: (state, action: PayloadAction<{ id: string; changes: Partial<Activity> }>) => {
      const { id, changes } = action.payload;
      const existing = state.entities[id];
      if (existing) {
        activitiesAdapter.updateOne(state, {
          id,
          changes: {
            ...changes,
            _optimistic: true,
            _version: (existing._version || 0) + 1,
          },
        });
      }
    },
    // Optimistic delete
    optimisticDelete: (state, action: PayloadAction<string>) => {
      activitiesAdapter.removeOne(state, action.payload);
    },
    // Rollback optimistic action
    rollbackOptimistic: (state, action: PayloadAction<string>) => {
      // Remove optimistic entry or restore previous version
      const activity = state.entities[action.payload];
      if (activity?._optimistic) {
        activitiesAdapter.removeOne(state, action.payload);
      }
    },
    // Clear all activities (for logout)
    clearActivities: (state) => {
      activitiesAdapter.removeAll(state);
      state.error = null;
      state.lastSyncTime = null;
    },
    // Mark activity as synced
    markSynced: (state, action: PayloadAction<{ localId: string; serverId: string; serverData: Activity }>) => {
      const { localId, serverId, serverData } = action.payload;
      // Remove optimistic entry
      activitiesAdapter.removeOne(state, localId);
      // Add server version
      activitiesAdapter.addOne(state, {
        ...serverData,
        _optimistic: false,
      });
    },
  },
  extraReducers: (builder) => {
    builder
      // Create activity
      .addCase(createActivity.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(createActivity.fulfilled, (state, action) => {
        state.loading = false;
        const serverActivity = action.payload.data;
        // Replace optimistic entry with server data
        const optimisticId = action.meta.arg.id || action.meta.requestId;
        if (state.entities[optimisticId]?._optimistic) {
          activitiesAdapter.removeOne(state, optimisticId);
        }
        activitiesAdapter.addOne(state, {
          ...serverActivity,
          _optimistic: false,
        });
      })
      .addCase(createActivity.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
        // Rollback optimistic entry
        const optimisticId = action.meta.arg.id || action.meta.requestId;
        if (state.entities[optimisticId]?._optimistic) {
          activitiesAdapter.removeOne(state, optimisticId);
        }
      })
      // Fetch activities
      .addCase(fetchActivities.pending, (state) => {
        state.loading = true;
        state.syncStatus = 'syncing';
      })
      .addCase(fetchActivities.fulfilled, (state, action) => {
        state.loading = false;
        state.syncStatus = 'synced';
        state.lastSyncTime = new Date().toISOString();
        // Merge server data with local optimistic entries
        const serverActivities = action.payload.map((a: Activity) => ({
          ...a,
          _optimistic: false,
        }));
        activitiesAdapter.upsertMany(state, serverActivities);
      })
      .addCase(fetchActivities.rejected, (state, action) => {
        state.loading = false;
        state.syncStatus = 'error';
        state.error = action.error.message || 'Failed to fetch activities';
      })
      // Update activity
      .addCase(updateActivity.fulfilled, (state, action) => {
        const serverActivity = action.payload.data;
        activitiesAdapter.updateOne(state, {
          id: serverActivity.id,
          changes: {
            ...serverActivity,
            _optimistic: false,
          },
        });
      })
      .addCase(updateActivity.rejected, (state, action) => {
        state.error = action.payload as string;
        // Rollback optimistic update
        const id = action.meta.arg.id;
        if (state.entities[id]?._optimistic) {
          // TODO: Restore previous version from history
        }
      })
      // Delete activity
      .addCase(deleteActivity.fulfilled, (state, action) => {
        activitiesAdapter.removeOne(state, action.payload);
      })
      .addCase(deleteActivity.rejected, (state, action) => {
        state.error = action.payload as string;
      });
  },
});

export const {
  optimisticCreate,
  optimisticUpdate,
  optimisticDelete,
  rollbackOptimistic,
  clearActivities,
  markSynced,
} = activitiesSlice.actions;

// Export selectors
export const activitiesSelectors = activitiesAdapter.getSelectors<RootState>(
  (state) => state.activities
);

// Custom selectors
export const selectActivitiesByChild = (state: RootState, childId: string) =>
  activitiesSelectors
    .selectAll(state)
    .filter((activity) => activity.childId === childId);

export const selectPendingActivities = (state: RootState) =>
  activitiesSelectors
    .selectAll(state)
    .filter((activity) => activity._optimistic);

export const selectActivitiesByType = (state: RootState, type: Activity['type']) =>
  activitiesSelectors
    .selectAll(state)
    .filter((activity) => activity.type === type);

export default activitiesSlice.reducer;
