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

export interface Child {
  id: string;
  familyId: string;
  name: string;
  birthDate: string;
  gender: 'male' | 'female' | 'other';
  photoUrl?: string;
  photoAlt?: string;
  displayColor: string;
  sortOrder: number;
  nickname?: string;
  medicalInfo?: any;
  createdAt: string;
  updatedAt?: string;
  // Offline metadata
  _optimistic?: boolean;
  _localId?: string;
  _version?: number;
}

// Create entity adapter
const childrenAdapter = createEntityAdapter<Child>({
  selectId: (child) => child.id,
  // Sort by sortOrder (birth order) instead of createdAt
  sortComparer: (a, b) => a.sortOrder - b.sortOrder,
});

// Async thunks
export const fetchChildren = createAsyncThunk(
  'children/fetch',
  async (familyId: string) => {
    const children = await childrenApi.getChildren(familyId);
    return children;
  }
);

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);
    }
  }
);

interface ChildrenState {
  loading: boolean;
  error: string | null;
  selectedChildId: string | null;
  selectedChildIds: string[];
  defaultChildId: string | null;
  viewMode: 'auto' | 'tabs' | 'cards';
  lastSelectedPerScreen: Record<string, string>;
  lastSyncTime: string | null;
}

const childrenSlice = createSlice({
  name: 'children',
  initialState: childrenAdapter.getInitialState<ChildrenState>({
    loading: false,
    error: null,
    selectedChildId: null,
    selectedChildIds: [],
    defaultChildId: null,
    viewMode: 'auto',
    lastSelectedPerScreen: {},
    lastSyncTime: 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 (single)
    selectChild: (state, action: PayloadAction<string>) => {
      state.selectedChildId = action.payload;
      state.selectedChildIds = [action.payload];
      // Save to localStorage
      if (typeof window !== 'undefined') {
        localStorage.setItem('selectedChildId', action.payload);
      }
    },
    // Select multiple children
    selectChildren: (state, action: PayloadAction<string[]>) => {
      state.selectedChildIds = action.payload;
      state.selectedChildId = action.payload[0] || null;
    },
    // Toggle child selection (for multi-select)
    toggleChildSelection: (state, action: PayloadAction<string>) => {
      const childId = action.payload;
      const index = state.selectedChildIds.indexOf(childId);

      if (index >= 0) {
        state.selectedChildIds.splice(index, 1);
      } else {
        state.selectedChildIds.push(childId);
      }

      state.selectedChildId = state.selectedChildIds[0] || null;
    },
    // Set default child for quick actions
    setDefaultChild: (state, action: PayloadAction<string>) => {
      state.defaultChildId = action.payload;
      if (typeof window !== 'undefined') {
        localStorage.setItem('defaultChildId', action.payload);
      }
    },
    // Set view mode
    setViewMode: (state, action: PayloadAction<'auto' | 'tabs' | 'cards'>) => {
      state.viewMode = action.payload;
      if (typeof window !== 'undefined') {
        localStorage.setItem('childViewMode', action.payload);
      }
    },
    // Remember last selected child per screen
    setLastSelectedForScreen: (state, action: PayloadAction<{ screen: string; childId: string }>) => {
      state.lastSelectedPerScreen[action.payload.screen] = action.payload.childId;
      if (typeof window !== 'undefined') {
        localStorage.setItem('lastSelectedPerScreen', JSON.stringify(state.lastSelectedPerScreen));
      }
    },
    clearChildren: (state) => {
      childrenAdapter.removeAll(state);
      state.selectedChildId = null;
      state.selectedChildIds = [];
      state.defaultChildId = 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,
  selectChildren,
  toggleChildSelection,
  setDefaultChild,
  setViewMode,
  setLastSelectedForScreen,
  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 selectSelectedChildren = (state: RootState) => {
  const ids = state.children.selectedChildIds;
  return ids
    .map(id => state.children.entities[id])
    .filter((child): child is Child => child !== undefined);
};

export const selectDefaultChild = (state: RootState) => {
  const id = state.children.defaultChildId;
  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 const selectChildrenCount = (state: RootState) =>
  childrenSelectors.selectTotal(state);

export const selectViewMode = (state: RootState) => {
  const { viewMode } = state.children;
  const childrenCount = childrenSelectors.selectTotal(state);

  if (viewMode === 'auto') {
    return childrenCount <= 3 ? 'tabs' : 'cards';
  }

  return viewMode;
};

export const selectChildColor = (childId: string) => (state: RootState) => {
  const child = state.children.entities[childId];
  return child?.displayColor || '#FF6B9D';
};

export const selectLastSelectedForScreen = (screen: string) => (state: RootState) => {
  return state.children.lastSelectedPerScreen[screen];
};

export default childrenSlice.reducer;
