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

export interface Child {
  id: string;
  familyId: string;
  name: string;
  birthDate: string;
  gender: 'male' | 'female' | 'other';
  profilePhoto?: string;
  metadata?: Record<string, any>;
  createdAt: string;
  updatedAt: string;
  // Offline metadata
  _optimistic?: boolean;
  _localId?: string;
  _version?: number;
}

// Create entity adapter
const childrenAdapter = createEntityAdapter<Child>({
  selectId: (child) => child.id,
  sortComparer: (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
});

// Async thunks
export const fetchChildren = createAsyncThunk(
  'children/fetch',
  async (familyId: string) => {
    const response = await fetch(`/api/v1/children?familyId=${familyId}`);
    if (!response.ok) {
      throw new Error('Failed to fetch children');
    }
    const data = await response.json();
    return data.data;
  }
);

export const createChild = createAsyncThunk(
  'children/create',
  async (child: Omit<Child, 'id' | 'createdAt' | 'updatedAt'>, { rejectWithValue }) => {
    try {
      const response = await fetch('/api/v1/children', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(child),
      });

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

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

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

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

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

const childrenSlice = createSlice({
  name: 'children',
  initialState: childrenAdapter.getInitialState({
    loading: false,
    error: null as string | null,
    selectedChildId: null as string | null,
    lastSyncTime: null as string | null,
  }),
  reducers: {
    // Optimistic operations
    optimisticCreate: (state, action: PayloadAction<Child>) => {
      childrenAdapter.addOne(state, {
        ...action.payload,
        _optimistic: true,
        _localId: action.payload.id,
        _version: 1,
      });
    },
    optimisticUpdate: (state, action: PayloadAction<{ id: string; changes: Partial<Child> }>) => {
      const { id, changes } = action.payload;
      const existing = state.entities[id];
      if (existing) {
        childrenAdapter.updateOne(state, {
          id,
          changes: {
            ...changes,
            _optimistic: true,
            _version: (existing._version || 0) + 1,
          },
        });
      }
    },
    rollbackOptimistic: (state, action: PayloadAction<string>) => {
      const child = state.entities[action.payload];
      if (child?._optimistic) {
        childrenAdapter.removeOne(state, action.payload);
      }
    },
    markSynced: (state, action: PayloadAction<{ localId: string; serverId: string; serverData: Child }>) => {
      const { localId, serverId, serverData } = action.payload;
      childrenAdapter.removeOne(state, localId);
      childrenAdapter.addOne(state, {
        ...serverData,
        _optimistic: false,
      });
    },
    // Select child
    selectChild: (state, action: PayloadAction<string>) => {
      state.selectedChildId = action.payload;
    },
    clearChildren: (state) => {
      childrenAdapter.removeAll(state);
      state.selectedChildId = null;
      state.error = null;
    },
  },
  extraReducers: (builder) => {
    builder
      // Fetch children
      .addCase(fetchChildren.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchChildren.fulfilled, (state, action) => {
        state.loading = false;
        state.lastSyncTime = new Date().toISOString();
        const serverChildren = action.payload.map((c: Child) => ({
          ...c,
          _optimistic: false,
        }));
        childrenAdapter.upsertMany(state, serverChildren);
      })
      .addCase(fetchChildren.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message || 'Failed to fetch children';
      })
      // Create child
      .addCase(createChild.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(createChild.fulfilled, (state, action) => {
        state.loading = false;
        const serverChild = action.payload.data;
        const optimisticId = action.meta.arg.id || action.meta.requestId;
        if (state.entities[optimisticId]?._optimistic) {
          childrenAdapter.removeOne(state, optimisticId);
        }
        childrenAdapter.addOne(state, {
          ...serverChild,
          _optimistic: false,
        });
      })
      .addCase(createChild.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
        const optimisticId = action.meta.arg.id || action.meta.requestId;
        if (state.entities[optimisticId]?._optimistic) {
          childrenAdapter.removeOne(state, optimisticId);
        }
      })
      // Update child
      .addCase(updateChild.fulfilled, (state, action) => {
        const serverChild = action.payload.data;
        childrenAdapter.updateOne(state, {
          id: serverChild.id,
          changes: {
            ...serverChild,
            _optimistic: false,
          },
        });
      })
      .addCase(updateChild.rejected, (state, action) => {
        state.error = action.payload as string;
      });
  },
});

export const {
  optimisticCreate,
  optimisticUpdate,
  rollbackOptimistic,
  markSynced,
  selectChild,
  clearChildren,
} = childrenSlice.actions;

// Export selectors
export const childrenSelectors = childrenAdapter.getSelectors<RootState>(
  (state) => state.children
);

// Custom selectors
export const selectSelectedChild = (state: RootState) => {
  const id = state.children.selectedChildId;
  return id ? state.children.entities[id] : null;
};

export const selectChildrenByFamily = (state: RootState, familyId: string) =>
  childrenSelectors
    .selectAll(state)
    .filter((child) => child.familyId === familyId);

export const selectPendingChildren = (state: RootState) =>
  childrenSelectors
    .selectAll(state)
    .filter((child) => child._optimistic);

export default childrenSlice.reducer;
