import { createSlice } from "@reduxjs/toolkit";
import { RangeInFile, SerializedDebugContext } from "../../../../src/client";
import { RootStore } from "../store";

export const debugStateSlice = createSlice({
  name: "debugState",
  initialState: {
    debugContext: {
      rangesInFiles: [],
      filesystem: {},
      traceback: undefined,
      description: undefined,
    },
    rangesMask: [],
  } as RootStore["debugState"],
  reducers: {
    updateValue: (
      state: RootStore["debugState"],
      action: {
        type: string;
        payload: { key: keyof SerializedDebugContext; value: any };
      }
    ) => {
      return {
        ...state,
        debugContext: {
          ...state.debugContext,
          [action.payload.key]: action.payload.value,
        },
      };
    },
    addRangeInFile: (
      state: RootStore["debugState"],
      action: {
        type: string;
        payload: {
          rangeInFile: RangeInFile;
          canUpdateLast: boolean;
        };
      }
    ) => {
      let rangesInFiles = state.debugContext.rangesInFiles;
      // If identical to existing range, don't add. Ideally you check for overlap of ranges.
      for (let range of rangesInFiles) {
        if (
          range.filepath === action.payload.rangeInFile.filepath &&
          range.range.start.line ===
            action.payload.rangeInFile.range.start.line &&
          range.range.end.line === action.payload.rangeInFile.range.end.line
        ) {
          return state;
        }
      }

      if (
        action.payload.canUpdateLast &&
        rangesInFiles.length > 0 &&
        rangesInFiles[rangesInFiles.length - 1].filepath ===
          action.payload.rangeInFile.filepath
      ) {
        return {
          ...state,
          debugContext: {
            ...state.debugContext,
            rangesInFiles: [
              ...rangesInFiles.slice(0, rangesInFiles.length - 1),
              action.payload.rangeInFile,
            ],
          },
        };
      } else {
        return {
          ...state,
          debugContext: {
            ...state.debugContext,
            rangesInFiles: [
              ...state.debugContext.rangesInFiles,
              action.payload.rangeInFile,
            ],
          },
          rangesMask: [...state.rangesMask, true],
        };
      }
    },
    deleteRangeInFileAt: (
      state: RootStore["debugState"],
      action: {
        type: string;
        payload: number;
      }
    ) => {
      return {
        ...state,
        debugContext: {
          ...state.debugContext,
          rangesInFiles: state.debugContext.rangesInFiles.filter(
            (_, index) => index !== action.payload
          ),
        },
        rangesMask: state.rangesMask.filter(
          (_, index) => index !== action.payload
        ),
      };
    },
    toggleSelectionAt: (
      state: RootStore["debugState"],
      action: {
        type: string;
        payload: number;
      }
    ) => {
      return {
        ...state,
        rangesMask: state.rangesMask.map((_, index) =>
          index === action.payload
            ? !state.rangesMask[index]
            : state.rangesMask[index]
        ),
      };
    },
    updateFileSystem: (
      state: RootStore["debugState"],
      action: {
        type: string;
        payload: { [filepath: string]: string };
      }
    ) => {
      return {
        ...state,
        debugContext: {
          ...state.debugContext,
          filesystem: {
            ...state.debugContext.filesystem,
            ...action.payload,
          },
        },
      };
    },
  },
});

export const {
  updateValue,
  updateFileSystem,
  addRangeInFile,
  deleteRangeInFileAt,
  toggleSelectionAt,
} = debugStateSlice.actions;
export default debugStateSlice.reducer;