/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import type {Element} from 'react-devtools-shared/src/frontend/types';

import * as React from 'react';
import {useContext, useMemo} from 'react';
import {TreeStateContext} from './TreeContext';
import {SettingsContext} from '../Settings/SettingsContext';
import TreeFocusedContext from './TreeFocusedContext';
import {StoreContext} from '../context';
import {useSubscription} from '../hooks';

import styles from './SelectedTreeHighlight.css';

type Data = {
  startIndex: number,
  stopIndex: number,
};

export default function SelectedTreeHighlight(_: {}): React.Node {
  const {lineHeight} = useContext(SettingsContext);
  const store = useContext(StoreContext);
  const treeFocused = useContext(TreeFocusedContext);
  const {ownerID, selectedElementID} = useContext(TreeStateContext);

  const subscription = useMemo(
    () => ({
      getCurrentValue: () => {
        if (
          selectedElementID === null ||
          store.isInsideCollapsedSubTree(selectedElementID)
        ) {
          return null;
        }

        const element = store.getElementByID(selectedElementID);
        if (
          element === null ||
          element.isCollapsed ||
          element.children.length === 0
        ) {
          return null;
        }

        const startIndex = store.getIndexOfElementID(element.children[0]);
        if (startIndex === null) {
          return null;
        }

        let stopIndex = null;
        let current: null | Element = element;
        while (current !== null) {
          if (current.isCollapsed || current.children.length === 0) {
            // We've found the last/deepest descendant.
            stopIndex = store.getIndexOfElementID(current.id);
            current = null;
          } else {
            const lastChildID = current.children[current.children.length - 1];
            current = store.getElementByID(lastChildID);
          }
        }

        if (stopIndex === null) {
          return null;
        }

        return {
          startIndex,
          stopIndex,
        };
      },
      subscribe: (callback: Function) => {
        store.addListener('mutated', callback);
        return () => {
          store.removeListener('mutated', callback);
        };
      },
    }),
    [selectedElementID, store],
  );
  const data = useSubscription<Data | null>(subscription);

  if (ownerID !== null) {
    return null;
  }

  if (data === null) {
    return null;
  }

  const {startIndex, stopIndex} = data;

  return (
    <div
      className={treeFocused ? styles.Active : styles.Inactive}
      style={{
        position: 'absolute',
        top: `${startIndex * lineHeight}px`,
        height: `${(stopIndex + 1 - startIndex) * lineHeight}px`,
      }}
    />
  );
}