// resources\assets\ts\DataPage\tableSlice.ts
import {
  PayloadAction,
  createAsyncThunk,
  createEntityAdapter,
  createSelector,
  createSlice
} from '@reduxjs/toolkit';
import { RootState } from './rootReducer';
import { fetchAll } from './dataSlice';
import { rowsPerPage, saveRowsPerPage } from './localstorage';
import axios from 'axios';

export type TableDataType = {
  id: number;
  erg_lngid: string;
  erg_krzl: string;
  erg_strerl?: number;
  erg_strdat: string;
  dya_nextaufgabe?: string;
  erg_clone: number;
  a1_agb_id: number;
  agb_id: number;
  a1_agb_gruppenid: number;
  agb_activefunc: number;
  color: string;
  task_type: string;
  task_name: string;
  task: string;
  current_task: string;
  task_comment: string;
  done_at: string;
  group_ID: number;
  comment_count: number;
  point_count: number;
  picture_count: number;
  aud_count: number;
  isBlocked: boolean;
  isPlanned: boolean;
  tags?: string[];
};
const tableAdapter = createEntityAdapter<TableDataType>();

export interface UpcomingTask {
  agb_id: number;
  agb_name: string;
  agb_nextaufgabe: string;
  agb_typ: string;
  agb_htmlinfos: string;
  agb_kurzbemerkung: string;
}
const upcomingTaskAdapter = createEntityAdapter<UpcomingTask>({
  selectId: (d) => d.agb_id
});

interface GroupPath {
  id: number;
  path: string[];
}
const groupsAdapter = createEntityAdapter<GroupPath>();

type Direction = 'none' | 'next' | 'prev';
type PageCursor = {
  firstID: null | number;
  lastID: null | number;
};
type State = {
  tables: ReturnType<typeof tableAdapter.getInitialState>;
  upcomingTasks: ReturnType<typeof upcomingTaskAdapter.getInitialState>;
  groupsPaths: ReturnType<typeof groupsAdapter.getInitialState>;
  readLogs: {};
  agbsToFilter: number[];
  paginationIndex: number;
  rowsPerPage: number;
  firstID: null | number;
  lastID: null | number;
  direction: Direction;
  isDisableNext: boolean;
  isShowHtmlInfo?: number;
  isOnDetailSearch: boolean;
  pageStack: PageCursor[];
};

const initialState: State = {
  tables: tableAdapter.getInitialState(),
  upcomingTasks: upcomingTaskAdapter.getInitialState(),
  groupsPaths: groupsAdapter.getInitialState(),
  readLogs: {},
  agbsToFilter: [],
  paginationIndex: 0,
  rowsPerPage: rowsPerPage(),
  firstID: null,
  lastID: null,
  direction: null,
  isDisableNext: false,
  isShowHtmlInfo: null,
  isOnDetailSearch: false,
  pageStack: [{ firstID: null, lastID: null }],
};
const slice = createSlice({
  name: 'monitor/table',
  initialState,
  reducers: {
    setTable(state, action) {
      const rows = action.payload;

      if (rows.length === 0) {
        if (state.direction === 'next') {
          state.isDisableNext = true;
        }
        return;
      }
      tableAdapter.upsertMany(state.tables, rows);
      state.firstID = rows[0]?.id ?? null;
      state.lastID = rows[rows.length - 1]?.id ?? null;

      if (state.direction === 'next') {
        state.pageStack.push({ firstID: state.firstID, lastID: state.lastID }); // Push new page cursors to stack
      } else if (state.direction === 'prev') {
        if (state.pageStack.length > 1) { // Pop from stack 
          state.pageStack.pop();
        }
      } else {
        state.pageStack = [{ firstID: state.firstID, lastID: state.lastID }]; // Direction is 'none' or null - reset stack
      }

      // Disable next only if we received fewer rows than requested
      state.isDisableNext = rows.length < state.rowsPerPage;
    },
    setUpcomingTasks(state, action) {
      const rows = action.payload;

      if (rows.length === 0) {
        state.isDisableNext = true;
        return;
      }
      upcomingTaskAdapter.upsertMany(state.upcomingTasks, rows);
      state.isDisableNext = rows.length < state.rowsPerPage;
    },

    clearTable(state) {
      state.tables = tableAdapter.getInitialState();
      state.upcomingTasks = upcomingTaskAdapter.getInitialState();
      state.paginationIndex = 0;
      state.agbsToFilter = [];
      state.isOnDetailSearch = false;
      state.isDisableNext = false;
      state.pageStack = [{ firstID: null, lastID: null }];
    },

    addAgbsToFilter(state, { payload }: PayloadAction<number[]>) {
      state.agbsToFilter = state.agbsToFilter.concat(payload);
    },

    setGroupPaths(state, { payload }: PayloadAction<GroupPath[]>) {
      groupsAdapter.upsertMany(state.groupsPaths, payload);
    },

    setRowsPerPage(state, { payload }) {
      state.rowsPerPage = payload;
      saveRowsPerPage(payload);
    },

    setPaginationIndex(state, { payload }: PayloadAction<number>) {
      state.paginationIndex = payload;
    },

    setDirection(state, { payload }: PayloadAction<Direction>) {
      state.direction = payload;
      state.isDisableNext = false;
    },

    setIsDisableNext(state, { payload }) {
      state.isDisableNext = payload;
    },

    setReadLogs(state, { payload }) {
      for (let log of payload) {
        const agbID = log.agb_id;
        const ergID = log.erg_id;
        if (!state.readLogs[ergID]) {
          state.readLogs[ergID] = [];
        }
        state.readLogs[ergID].push(agbID);
      }
    },

    markRead(state, { payload }: PayloadAction<{ agbID: number; ergID: number }>) {
      const { ergID, agbID } = payload;

      if (!state.readLogs[ergID]) {
        state.readLogs[ergID] = [];
      }

      const index = state.readLogs[ergID].indexOf(agbID);

      if (index !== -1) {
        state.readLogs[ergID].splice(index, 1);
      } else {
        state.readLogs[ergID].push(agbID);
      }
    },

    resetPagination(state) {
      state.firstID = null;
      state.lastID = null;
      state.direction = null;
      state.pageStack = [{ firstID: null, lastID: null }];
    },

    setFirstID(state, action) {
      state.firstID = action.payload;
    },

    setLastID(state, action) {
      state.lastID = action.payload;
    },

    toggleRead(state, { payload }: PayloadAction<{ ergID: number; agbID: number }>) {
      const { ergID, agbID } = payload;

      if (!state.readLogs[ergID]) {
        state.readLogs[ergID] = [];
      }

      const index = state.readLogs[ergID].indexOf(agbID);

      if (index !== -1) {
        state.readLogs[ergID].splice(index, 1);
      } else {
        state.readLogs[ergID].push(agbID);
      }
    },

    toggleShowHtmlInfos(state, { payload }: PayloadAction<number>) {
      if (state.isShowHtmlInfo === payload) {
        state.isShowHtmlInfo = null;
        return;
      }

      state.isShowHtmlInfo = payload;
    },

    setIsOnDetailSearch(state, { payload }) {
      state.isOnDetailSearch = payload;
    }
  }
});


export const {
  setTable,
  setGroupPaths,
  clearTable,
  setUpcomingTasks,
  setReadLogs,
  addAgbsToFilter,
  toggleShowHtmlInfos,
  setIsOnDetailSearch,
  setRowsPerPage,
  setDirection,
  setIsDisableNext,
  setPaginationIndex,
  setFirstID,
  setLastID,
  resetPagination
} = slice.actions;

export const markAsRead = createAsyncThunk(
  'monitor/mark_ticket_as_read',
  async (erg_id: number, thunkAPI) => {
    const rootState = thunkAPI.getState() as RootState;
    const tableRowItem = rootState.table.tables.entities[erg_id];
    if (tableRowItem === undefined) {
      return thunkAPI.rejectWithValue(new Error(`ergID: ${erg_id} not found`));
    }
    const agbID = tableRowItem.a1_agb_id ?? tableRowItem.agb_id;
    thunkAPI.dispatch(slice.actions.markRead({ agbID, ergID: erg_id }));
  }
);
export const toggleRead = createAsyncThunk(
  'monitor/mark_ticket_as_read',
  async (erg_id: number, thunkAPI) => {
    await axios.get(`c/${erg_id}/readLog`);

    const rootState = thunkAPI.getState() as RootState;
    const tableRowItem = rootState.table.tables.entities[erg_id];
    if (!tableRowItem) {
      return thunkAPI.rejectWithValue(`ergID ${erg_id} not found`);
    }

    const agbID = tableRowItem.a1_agb_id ?? tableRowItem.agb_id;
    thunkAPI.dispatch(slice.actions.toggleRead({ agbID, ergID: erg_id }));
  }
);

const tableSelectors = tableAdapter.getSelectors(
  (s: RootState) => s.table.tables
);
const tableIndexSelector = ({ table }: RootState) => table.paginationIndex;
export const onDetailSearchResultLimit = 100;
const rowsCountSelector = ({ table }: RootState) => table.isOnDetailSearch
  ? onDetailSearchResultLimit : table.rowsPerPage;

const groupPathsSelectors = groupsAdapter.getSelectors(
  ({ table }: RootState) => table.groupsPaths
);
export const selectGroupEntities = groupPathsSelectors.selectEntities;

export const upcomingTaskSelector = upcomingTaskAdapter.getSelectors(
  (s: RootState) => s.table.upcomingTasks
);

export const selectTable = createSelector(
  tableSelectors.selectEntities,
  tableSelectors.selectIds,
  tableIndexSelector,
  rowsCountSelector,
  (tables, ids, tableIndex, rowCount) => {
    const idsToGet = ids.slice(
      tableIndex * rowCount,
      tableIndex * rowCount + rowCount
    );
    return idsToGet.map((id) => tables[id]);
  }
);

export default slice.reducer;
