/**
 * Copyright (c) OpenLens Authors. All rights reserved.
 * Licensed under MIT License. See LICENSE in root directory for more information.
 */
import { Tabs } from "../../../../renderer/components/tabs";
import React from "react";
import type { Composite } from "../../../../common/utils/composite/get-composite/get-composite";
import type { PreferenceTypes } from "../preference-items/preference-item-injection-token";
import { Map } from "../../../../renderer/components/map/map";
import { withInjectables } from "@ogre-tools/injectable-react";
import type { IComputedValue } from "mobx";
import preferencesCompositeInjectable from "../preference-items/preferences-composite.injectable";
import { observer } from "mobx-react";
import { PreferencesNavigationTab } from "./preferences-navigation-tab";
import { compositeHasDescendant } from "../../../../common/utils/composite/composite-has-descendant/composite-has-descendant";
import type { PreferenceTabsRoot } from "../preference-items/preference-tab-root";
import { Icon } from "../../../../renderer/components/icon";
import { checkThatAllDiscriminablesAreExhausted } from "../../../../common/utils/composable-responsibilities/discriminable/discriminable";

interface Dependencies {
  composite: IComputedValue<Composite<PreferenceTypes | PreferenceTabsRoot>>;
}

const NonInjectedPreferencesNavigation = observer(({ composite }: Dependencies) => (
  <Tabs className="flex column" scrollable={false}>
    {toNavigationHierarchy(composite.get())}
  </Tabs>
));

export const PreferencesNavigation = withInjectables<Dependencies>(
  NonInjectedPreferencesNavigation,

  {
    getProps: (di) => ({
      composite: di.inject(preferencesCompositeInjectable),
    }),
  },
);

const toNavigationHierarchy = (composite: Composite<PreferenceTypes | PreferenceTabsRoot>) => {
  // Note: This makes tab groups and tabs without content not render anything in navigation.
  if (!hasContent(composite)) {
    return emptyRender;
  }

  const value = composite.value;

  switch (value.kind) {
    // Note: These preference item types are not rendered in navigation,
    // yet they are interesting for deciding if eg. a tab group or a tab has content
    // somewhere in structure, and therefore not be hidden.
    case "page": {
      return emptyRender;
    }

    case "block": {
      return emptyRender;
    }

    case "tab-group": {
      return (
        <div data-preference-tab-group-test={value.id}>
          <div className="header flex items-center">
            {value.iconName && (
              <Icon
                material={value.iconName}
                smallest
                className="mr-3"
              />
            )}
            {value.label}
          </div>

          <Map items={composite.children}>{toNavigationHierarchy}</Map>
        </div>
      );
    }

    case "tab": {
      return <PreferencesNavigationTab tab={value} />;
    }

    case "preference-tabs-root": {
      return (
        <Map items={composite.children} getSeparator={value.childSeparator}>
          {toNavigationHierarchy}
        </Map>
      );
    }

    default: {
      throw checkThatAllDiscriminablesAreExhausted(value);
    }
  }
};

const hasContent = compositeHasDescendant<PreferenceTypes | PreferenceTabsRoot>(
  (composite) => composite.value.kind === "block",
);

const emptyRender = <></>;


