import { useState } from 'react';
import clsx from 'clsx';
import { Link1Icon, LinkNone1Icon } from '@radix-ui/react-icons';
import { DropdownMenu } from '@radix-ui/themes';

import { useAppDispatch, useAppSelector } from '@/app/hooks';
import {
  isEvaluatedComponentModel,
  selectModel,
  updateExistingComponentValues,
} from '@/features/layout/layoutModelSlice';
import { selectSelectedComponentUuid } from '@/features/ui/uiSlice';

import type {
  ComponentModel,
  DynamicPropSource,
  EvaluatedComponentModel,
} from '@/features/layout/layoutModelSlice';

import styles from './PropLinker.module.css';

export interface LinkSuggestion {
  label: string;
  source: any;
}

export interface PropLinkerProps {
  propName: string;
  linked: boolean;
  suggestions: {
    [suggestionKey: string]: LinkSuggestion;
  };
}

/**
 * Appears as a link icon. When clicked, a dropdown appears with
 * suggestions for linking this field to other fields.
 * @param {string} propName
 *   The machine name of the prop being linked.
 * @param {boolean} linked
 *   Whether the field is currently linked.
 * @param {object} suggestions
 *   An object of suggested fields to link to, keyed by a unique identifier.
 *   This list is generated by  \Drupal\canvas\ShapeMatcher\FieldForComponentSuggester,
 *   Each suggestion contains:
 *   - label: The human-readable name of the field.
 *   - source: An object containing the dynamic expression that results in the
 *     prop resolving to the linked field's value.
 */
const PropLinker = ({ propName, linked, suggestions }: PropLinkerProps) => {
  const model = useAppSelector(selectModel);
  const selectedComponent = useAppSelector(selectSelectedComponentUuid);
  const dispatch = useAppDispatch();
  const selectedComponentId: string = selectedComponent || 'noop';
  const selectedModel: ComponentModel | EvaluatedComponentModel =
    model[selectedComponentId] || {};
  const [linkerOpen, setLinkerOpen] = useState(false);
  const handleFieldClick = (value: LinkSuggestion) => {
    dispatch(
      updateExistingComponentValues({
        componentToUpdateId: selectedComponentId,
        values: {
          [propName]: 'noop',
        },
        sources: {
          [propName]: value.source,
        },
      }),
    );
  };

  let currentExpression = undefined;
  if (
    isEvaluatedComponentModel(selectedModel) &&
    selectedModel?.source?.[propName] &&
    Object.prototype.hasOwnProperty.call(
      Object(selectedModel.source[propName] || {}),
      'expression',
    )
  ) {
    const fieldSource = selectedModel.source[propName] as DynamicPropSource;
    currentExpression = fieldSource.expression;
  }

  return (
    <DropdownMenu.Root onOpenChange={(open) => setLinkerOpen(open)}>
      <DropdownMenu.Trigger>
        <span
          className={clsx(styles.linker, {
            [styles.linkerOpen]: linkerOpen,
          })}
        >
          {linked && <Link1Icon className={styles.default} />}
          {!linked && <LinkNone1Icon className={styles.default} />}
        </span>
      </DropdownMenu.Trigger>
      <DropdownMenu.Content align="end" side="bottom">
        {Object.entries(suggestions || {}).map(([key, value]) => (
          <DropdownMenu.Item
            key={key}
            onClick={() => handleFieldClick(value as LinkSuggestion)}
            disabled={value.source.expression === currentExpression}
            className={clsx({
              [styles.disabled]: value.source.expression === currentExpression,
            })}
          >
            {value.source.expression === currentExpression && '(active) '}
            {(value as LinkSuggestion).label}
          </DropdownMenu.Item>
        ))}
      </DropdownMenu.Content>
    </DropdownMenu.Root>
  );
};

export default PropLinker;
