import {
  Pane,
  PaneId,
  PresenceIndicator,
  SearchFileVisibility,
  SearchResults,
  ShareDBDoc,
  Username,
} from '../../types';
import { VizFileId, VizContent } from '@vizhub/viz-types';
import { ThemeLabel } from '../themes';
import { closeTabsReducer } from './closeTabsReducer';
import { openTabReducer } from './openTabReducer';
import { setActiveFileIdReducer } from './setActiveFileIdReducer';
import {
  setActiveFileLeftReducer,
  setActiveFileRightReducer,
} from './setActiveFileLeftRightReducer';
import { setIsSettingsOpenReducer } from './setIsSettingsOpenReducer';
import { setIsDocOpenReducer } from './setIsDocOpenReducer';
import { setThemeReducer } from './setThemeReducer';
import { editorNoLongerWantsFocusReducer } from './editorNoLongerWantsFocusReducer';
import { setUsernameReducer } from './setUsernameReducer';
import {
  setIsSearchOpenReducer,
  setSearchReducer,
  setSearchResultsReducer,
  setSearchFileVisibilityReducer,
  setSearchLineVisibilityReducer,
  setSearchFocusedIndexReducer,
  toggleSearchFocusedReducer,
} from './searchReducer';
import { toggleAutoFollowReducer } from './toggleAutoFollowReducer';
import { updatePresenceIndicatorReducer } from './updatePresenceIndicatorReducer';
import { splitCurrentPaneReducer } from './splitCurrentPaneReducer';
export { createInitialState } from './createInitialState';

// The shape of the state managed by the reducer.
export type VZState = {
  // The state of the split pane (tree data structure).
  pane: Pane;

  // The id of the currently active pane.
  activePaneId: PaneId;

  // The theme that is currently active.
  theme: ThemeLabel;

  // Search pattern and most recent results based on the current pattern
  search: SearchResults;

  // True to show the search instead of files
  isSearchOpen: boolean;

  // True to show the settings modal.
  isSettingsOpen: boolean;

  isDocOpen: boolean;

  // True if the editor should focus on the next render.
  editorWantsFocus: boolean;

  // The username of the current user.
  username: Username;

  // True if "auto-follow" is enabled.
  // This is a feature that automatically scrolls the editor to the
  // currently active remote user's cursor position.
  enableAutoFollow: boolean;

  // The list of remote users and which file they have open,
  // for presence display in the sidebar.
  sidebarPresenceIndicators: Array<PresenceIndicator>;
};

// The shape of the actions that can be dispatched to the reducer.
export type VZAction =
  // `set_active_file_id`
  //  * Sets the active file ID.
  | { type: 'set_active_file_id'; activeFileId: VizFileId }

  // `set_active_file_left' 'set_active_file_right`
  //  * Sets the active file ID to be the tab directly to the left or right
  //  * of the currently active tab.
  | { type: 'set_active_file_left' }
  | { type: 'set_active_file_right' }

  // `open_tab`
  //  * Opens a tab.
  //  * Also serves to change an already open transient tab to persistent.
  | {
      type: 'open_tab';
      fileId: VizFileId;
      isTransient?: boolean;
    }

  // `close_tabs`
  //  * Closes a set of tabs.
  | {
      type: 'close_tabs';
      fileIdsToClose: Array<VizFileId>;
      // The pane id to close tabs from.
    }

  // `set_theme`
  //  * Sets the theme.
  | { type: 'set_theme'; themeLabel: ThemeLabel }

  // `set_is_settings_open`
  //  * Sets whether the settings modal is open.
  | { type: 'set_is_settings_open'; value: boolean }
  | { type: 'set_is_doc_open'; value: boolean }

  // `set_is_search_open`
  //  * Sets whether the search tab is open.
  | { type: 'set_is_search_open'; value: boolean }

  // `set_search`
  //  * Sets the current search pattern
  | { type: 'set_search'; value: string }

  // `set_search_results`
  //  * Sets the current search pattern
  | {
      type: 'set_search_results';
      files: ShareDBDoc<VizContent>;
    }

  // `set_search_results_visibility`
  //  * Sets the visibility of a current search pattern file
  | {
      type: 'set_search_file_visibility';
      files: ShareDBDoc<VizContent>;
      id: string;
      visibility: SearchFileVisibility;
    }

  // `hide_search_results_line`
  //  * Hides a current search pattern file's specific matching line
  | {
      type: 'hide_search_results_line';
      files: ShareDBDoc<VizContent>;
      id: string;
      line: number;
    }

  // `set_active_search_index`
  //  * Sets focused (file) index and child focused (line) index for search results
  | {
      type: 'set_active_search_index';
      focusedIndex: number;
      childIndex: number;
    }

  // `toggle_search_focused`
  // * Toggles focused variable to trigger search input focus
  | { type: 'toggle_search_focused' }

  // `editor_no_longer_wants_focus`
  //  * Sets `editorWantsFocus` to `false`.
  | { type: 'editor_no_longer_wants_focus' }

  // `set_username`
  //  * Sets the username.
  | { type: 'set_username'; username: Username }

  // `toggle_auto_follow`
  //  * Toggles the auto-follow feature.
  | { type: 'toggle_auto_follow' }

  // `update_presence_indicator
  //  * Updates a single presence indicator
  | {
      type: 'update_presence_indicator';
      presenceIndicator: PresenceIndicator;
    }

  // `split_current_pane`
  | { type: 'split_current_pane' };

const reducers = [
  setActiveFileIdReducer,
  setActiveFileLeftReducer,
  setActiveFileRightReducer,
  openTabReducer,
  closeTabsReducer,
  setThemeReducer,
  setSearchReducer,
  setSearchResultsReducer,
  setSearchFileVisibilityReducer,
  setSearchLineVisibilityReducer,
  setSearchFocusedIndexReducer,
  toggleSearchFocusedReducer,
  setIsSearchOpenReducer,
  setIsSettingsOpenReducer,
  setIsDocOpenReducer,
  editorNoLongerWantsFocusReducer,
  setUsernameReducer,
  toggleAutoFollowReducer,
  updatePresenceIndicatorReducer,
  splitCurrentPaneReducer,
];

export const vzReducer = (
  state: VZState,
  action: VZAction,
): VZState =>
  reducers.reduce(
    (currentState, currentReducer) =>
      currentReducer(currentState, action),
    state,
  );
