import { clsx } from 'clsx';

import { AriaLabelProperty, CommonProps, Heading, LinkProps, Typography } from '../common';
import Link from '../link';
import Title from '../title';
import React, { useEffect, useRef, FunctionComponent, ReactNode } from 'react';

type ActionProps = AriaLabelProperty & {
  text: string;
  onClick?: (event: React.MouseEvent) => void;
  disabled?: boolean;
};

type ButtonActionProps = ActionProps;
type LinkActionProps = ActionProps & LinkProps;

export interface HeaderProps extends CommonProps {
  /**
   * Optional prop to define the action for the header. If the `href` property
   * is provided, a `Link` will be rendered instead of a `Button`.
   */
  action?: ButtonActionProps | LinkActionProps;

  /**
   * Option prop to specify DOM render element of the title
   *
   * - When `as="legend"`, the `Header` will render as a `<legend>` element.
   *   **Note:** `<legend>` elements must be the first child of a `<fieldset>` to comply with HTML semantics.
   *   If this condition is not met, a warning will be logged to the console.
   *
   * - Other valid values include standard heading tags (`h1` to `h6`) or `header`.
   * @default 'h5'
   */
  as?: Heading | 'legend' | 'header';

  /** Required prop to set the title of the Header. */
  title: ReactNode;

  /**
   * Optional prop to specify the level of the Header
   * @default 'group'
   */
  level?: 'section' | 'group';

  className?: string;
  testId?: string;
}

/**
 * Renders a header action which can be either a button or a link.
 *
 * @param {Object} props - The properties object.
 * @param {ButtonActionProps | LinkActionProps} props.action - The action object which can be either a button or a link.
 * @returns {JSX.Element} The rendered header action component.
 */
const HeaderAction = React.forwardRef<
  HTMLButtonElement | HTMLAnchorElement,
  { action: ButtonActionProps | LinkActionProps }
>(({ action }, ref) => {
  return (
    <Link
      className="np-header__action-button"
      aria-label={action['aria-label']}
      href={'href' in action ? action.href : undefined}
      target={'target' in action ? action.target : undefined}
      disabled={action.disabled}
      onClick={action.onClick}
    >
      {action.text}
    </Link>
  );
});

HeaderAction.displayName = 'HeaderAction';

/**
 * @param {ButtonActionProps | LinkActionProps} [action] - Optional prop to specify the action button or link.
 * @param {Heading | 'legend'} [as='h5'] - Optional prop to override the heading element rendered for the title.
 * @param {string} title - Required prop to set the title of the section header.
 * @param {'group' | 'section'} [level='group'] - Optional prop to specify the level of the section header.
 * @param {string} [className]
 * @param {string} [testId]
 *
 * @see {@link Header } for further information.
 * @see {@link https://storybook.wise.design/?path=/docs/typography-header--docs|Storybook Wise Design}
 */
const Header: FunctionComponent<HeaderProps> = React.forwardRef(
  (
    { as = 'h5', action, className, testId, title, level = 'group', ...props },
    ref: React.Ref<HTMLDivElement | HTMLHeadingElement | HTMLLegendElement>,
  ) => {
    const internalRef = useRef<HTMLLegendElement>(null);
    const levelTypography =
      level === 'group' ? Typography.TITLE_GROUP : Typography.TITLE_SUBSECTION;
    const headerClasses = clsx('np-header', className, {
      'np-header--group': level === 'group',
    });

    const commonProps = {
      className: headerClasses,
      'data-testid': testId,
    };

    useEffect(() => {
      if (as === 'legend' && internalRef.current) {
        const { parentElement } = internalRef.current;
        if (parentElement?.tagName.toLowerCase() !== 'fieldset') {
          console.warn(
            'Legends should be the first child in a fieldset, and this is not possible when including an action',
          );
        }
      }
    }, [as]);

    if (!action) {
      return (
        <Title ref={internalRef} as={as} type={levelTypography} {...commonProps} {...props}>
          {title}
        </Title>
      );
    }

    return (
      <div {...commonProps} {...props} ref={ref}>
        <Title as={as} type={levelTypography} className="np-header__title">
          {title}
        </Title>
        <HeaderAction action={action} />
      </div>
    );
  },
);

Header.displayName = 'Header';

export default Header;
