/**
 * 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.
 *
 * @format
 */

import React, {useState} from 'react';
import {plugin} from '../../index';
import {
  Button,
  Input,
  Modal,
  Tooltip,
  Typography,
  Space,
  Switch,
  Badge,
  Dropdown,
} from 'antd';
import {
  EyeOutlined,
  PauseCircleOutlined,
  AppstoreOutlined,
  PlayCircleOutlined,
  SearchOutlined,
} from '@ant-design/icons';
import {usePlugin, useValue, Layout} from 'flipper-plugin';
import {FrameworkEventMetadata, FrameworkEventType} from '../../ClientTypes';
import {
  buildTreeSelectData,
  FrameworkEventsTreeSelect,
} from '../shared/FrameworkEventsTreeSelect';
import {TraversalMode} from '../../DesktopTypes';

export const TreeControls: React.FC = () => {
  const instance = usePlugin(plugin);
  const searchTerm = useValue(instance.uiState.searchTerm);
  const isPaused = useValue(instance.uiState.isPaused);
  const filterMainThreadMonitoring = useValue(
    instance.uiState.filterMainThreadMonitoring,
  );

  const frameworkEventMonitoring: Map<FrameworkEventType, boolean> = useValue(
    instance.uiState.frameworkEventMonitoring,
  );

  const [showFrameworkEventsModal, setShowFrameworkEventsModal] =
    useState(false);

  const frameworkEventMetadata = useValue(instance.frameworkEventMetadata);

  const currentTraversalMode = useValue(instance.uiState.currentTraversalMode);
  const supportedTraversalModes = useValue(
    instance.uiState.supportedTraversalModes,
  );
  const labelForMode = (mode: TraversalMode) => {
    switch (mode) {
      case 'view-hierarchy':
        return 'UI Hierarchy';
      case 'accessibility-hierarchy':
        return 'Accessibility Hierarchy';
    }
  };

  const menus = supportedTraversalModes.map((mode) => ({
    key: mode,
    label: labelForMode(mode),
  }));

  return (
    <Layout.Horizontal gap="medium" pad="medium">
      {supportedTraversalModes.length > 1 ? (
        <Dropdown
          menu={{
            selectable: true,
            selectedKeys: [currentTraversalMode],
            items: menus,
            onSelect: async (event) => {
              const mode = event.selectedKeys[0] as TraversalMode;
              instance.uiActions.setCurrentTraversalMode(mode); // update UI
              await instance.onTraversalModeChange(mode); // update mobile client
            },
          }}>
          <Tooltip title="Debugger Mode">
            <Button shape="circle">
              <AppstoreOutlined />
            </Button>
          </Tooltip>
        </Dropdown>
      ) : null}
      <Input
        value={searchTerm}
        onChange={(e) => {
          instance.uiActions.onSearchTermUpdated(e.target.value);
        }}
        prefix={<SearchOutlined />}
        placeholder="Search"
      />
      <Button
        type="default"
        shape="circle"
        onClick={instance.uiActions.onPlayPauseToggled}
        icon={
          <Tooltip
            title={isPaused ? 'Resume live updates' : 'Pause incoming updates'}>
            {isPaused ? <PlayCircleOutlined /> : <PauseCircleOutlined />}
          </Tooltip>
        }></Button>
      {frameworkEventMonitoring.size > 0 && (
        <>
          <Badge
            size="small"
            count={
              [...frameworkEventMonitoring.values()].filter(
                (val) => val === true,
              ).length
            }>
            <Button
              type="default"
              shape="circle"
              onClick={() => {
                setShowFrameworkEventsModal(true);
              }}
              icon={
                <Tooltip title="Framework event monitoring">
                  <EyeOutlined />
                </Tooltip>
              }></Button>
          </Badge>
          <FrameworkEventsMonitoringModal
            metadata={frameworkEventMetadata}
            filterMainThreadMonitoring={filterMainThreadMonitoring}
            onSetFilterMainThreadMonitoring={
              instance.uiActions.onSetFilterMainThreadMonitoring
            }
            frameworkEventTypes={[...frameworkEventMonitoring.entries()]}
            onSetEventMonitored={
              instance.uiActions.onSetFrameworkEventMonitored
            }
            visible={showFrameworkEventsModal}
            onCancel={() => setShowFrameworkEventsModal(false)}
          />
        </>
      )}
    </Layout.Horizontal>
  );
};

function FrameworkEventsMonitoringModal({
  visible,
  onCancel,
  onSetEventMonitored,
  onSetFilterMainThreadMonitoring,
  filterMainThreadMonitoring,
  frameworkEventTypes,
  metadata,
}: {
  metadata: Map<FrameworkEventType, FrameworkEventMetadata>;
  visible: boolean;
  onCancel: () => void;
  onSetEventMonitored: (
    eventType: FrameworkEventType,
    monitored: boolean,
  ) => void;
  filterMainThreadMonitoring: boolean;
  onSetFilterMainThreadMonitoring: (toggled: boolean) => void;
  frameworkEventTypes: [FrameworkEventType, boolean][];
}) {
  const selectedFrameworkEvents = frameworkEventTypes
    .filter(([, selected]) => selected)
    .map(([eventType]) => eventType);

  const treeData = buildTreeSelectData(
    frameworkEventTypes.map(([type]) => type),
    metadata,
  );

  return (
    <Modal
      title="Framework event monitoring"
      open={visible}
      footer={null}
      onCancel={onCancel}>
      <Space direction="vertical" size="large">
        <Typography.Text>
          Monitoring an event will cause the relevant node in the visualizer and
          tree to highlight briefly. Additionally counter will show the number
          of matching events in the tree
        </Typography.Text>

        <FrameworkEventsTreeSelect
          placeholder="Select node types to monitor"
          onSetEventSelected={onSetEventMonitored}
          selected={selectedFrameworkEvents}
          treeData={treeData}
        />

        <Layout.Horizontal gap="medium">
          <Switch
            checked={filterMainThreadMonitoring}
            onChange={(event) => {
              onSetFilterMainThreadMonitoring(event);
            }}
          />
          <Typography.Text>
            Only highlight events that occured on the main thread
          </Typography.Text>
        </Layout.Horizontal>
      </Space>
    </Modal>
  );
}
