export interface ApplicationWorkspaceSnapshot<ViewId extends string = string> {
  navigationOpen: boolean;
  activeView: ViewId | null;
  contentOpen: boolean;
  contentExpanded: boolean;
}

export interface ApplicationWorkspaceController<ViewId extends string = string> {
  getState: () => ApplicationWorkspaceSnapshot<ViewId>;
  openNavigation: () => void;
  toggleNavigation: () => void;
  closeNavigation: () => void;
  openView: (view: ViewId) => void;
  closeView: () => void;
  setContentExpanded: (expanded: boolean) => void;
}

export interface ApplicationWorkspaceOptions<ViewId extends string = string> {
  root?: HTMLElement;
  navigationOpen?: boolean;
  activeView?: ViewId | null;
  contentExpanded?: boolean;
  onChange?: (state: ApplicationWorkspaceSnapshot<ViewId>) => void;
}

export function createApplicationWorkspaceController<ViewId extends string = string>({
  root,
  navigationOpen = false,
  activeView = null,
  contentExpanded = true,
  onChange,
}: ApplicationWorkspaceOptions<ViewId> = {}): ApplicationWorkspaceController<ViewId> {
  let state: ApplicationWorkspaceSnapshot<ViewId> = {
    navigationOpen: navigationOpen || activeView !== null,
    activeView,
    contentOpen: activeView !== null,
    contentExpanded,
  };

  const commit = (patch: Partial<ApplicationWorkspaceSnapshot<ViewId>>) => {
    state = { ...state, ...patch };
    state.contentOpen = state.activeView !== null;
    root?.toggleAttribute("data-navigation-open", state.navigationOpen);
    root?.toggleAttribute("data-content-open", state.contentOpen);
    root?.toggleAttribute("data-content-expanded", state.contentOpen && state.contentExpanded);
    onChange?.({ ...state });
  };

  commit({});

  return {
    getState: () => ({ ...state }),
    openNavigation: () => commit({ navigationOpen: true }),
    toggleNavigation: () => commit({ navigationOpen: !state.navigationOpen, activeView: state.navigationOpen ? null : state.activeView }),
    closeNavigation: () => commit({ navigationOpen: false, activeView: null }),
    openView: (view) => commit({ navigationOpen: true, activeView: view, contentExpanded: true }),
    closeView: () => commit({ activeView: null }),
    setContentExpanded: (expanded) => commit({ contentExpanded: expanded }),
  };
}
