import { createSlice } from '@reduxjs/toolkit';

import type { AddedModule, Project, VcsSyncStatus } from '../../types';
import {
  deleteProject,
  fetchAnyDeployed,
  fetchHubKey,
  fetchProject,
  fetchProjectModules,
  fetchProjectsList,
  fetchVcsSync
} from './thunks';

export interface ProjectsState {
  addedModules: AddedModule[];
  anyDeployed: boolean;
  current: Project | null;
  error: string | null;
  // undefined while the hub key is still loading; null only once a fetch has
  // resolved empty or failed (so the "hub not reported" warning doesn't flash on load).
  hubKey: string | null | undefined;
  list: Project[];
  loading: boolean;
  // False until the current project's modules have been fetched, so consumers
  // can tell "no modules yet loaded" apart from "loaded and empty".
  modulesLoaded: boolean;
  vcsSync: VcsSyncStatus | null;
}

const initialState: ProjectsState = {
  addedModules: [],
  anyDeployed: false,
  current: null,
  error: null,
  hubKey: undefined,
  list: [],
  loading: false,
  modulesLoaded: false,
  vcsSync: null
};

const projectsSlice = createSlice({
  name: 'projects',
  initialState,
  reducers: {
    clearCurrent(state) {
      state.current = null;
      state.addedModules = [];
    }
  },
  extraReducers: builder => {
    builder
      .addCase(fetchProjectsList.fulfilled, (state, { payload }) => {
        state.list = payload.data ?? [];
      })
      .addCase(fetchProject.pending, state => {
        state.loading = true;
        state.error = null;
        state.modulesLoaded = false;
      })
      .addCase(fetchProject.fulfilled, (state, { payload }) => {
        state.loading = false;
        state.current = payload;
      })
      .addCase(fetchProject.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message || 'Project not found.';
      })
      .addCase(fetchProjectModules.fulfilled, (state, { payload }) => {
        state.addedModules = payload ?? [];
        state.modulesLoaded = true;
      })
      .addCase(fetchVcsSync.fulfilled, (state, { payload }) => {
        state.vcsSync = payload;
      })
      .addCase(fetchAnyDeployed.fulfilled, (state, { payload }) => {
        state.anyDeployed = payload;
      })
      .addCase(fetchHubKey.fulfilled, (state, { payload }) => {
        state.hubKey = payload;
      })
      .addCase(fetchHubKey.rejected, state => {
        state.hubKey = null;
      })
      .addCase(deleteProject.fulfilled, state => {
        state.current = null;
      });
  }
});

export const { clearCurrent } = projectsSlice.actions;
export default projectsSlice.reducer;
