import { Children, HTMLAttributes, ReactNode, isValidElement, useState } from 'react';
import { LiveRegion, Sentiment, Typography } from '../../common';
import type { AriaLive } from '../../common';
import { GiftBox } from '@transferwise/icons';
import type { Sentiment as SurfaceSentiment } from '../../sentimentSurface';
import StatusIcon from '../../statusIcon';
import { clsx } from 'clsx';
import Body from '../../body';
import Link, { LinkProps } from '../../link';
import { PrimitivePrompt, PrimitivePromptProps } from '../PrimitivePrompt';

export type InfoPromptAction = Pick<LinkProps, 'href' | 'target' | 'onClick'> & {
  /**
   * The label text for the action link
   */
  label: string;
};

export type InfoPromptMedia = {
  /**
   * The icon/image asset to display.
   * The asset should include its own accessibility attributes (e.g. title, aria-label) if it conveys meaning.
   */
  asset: ReactNode;
};

export type InfoPromptProps = Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'aria-live' | 'role'> &
  Pick<PrimitivePromptProps, 'data-testid'> & {
    /**
     * The sentiment determines the colour scheme
     * @default 'neutral'
     */
    sentiment?: SurfaceSentiment;
    /**
     * Handler called when the close button is clicked.
     * If not provided, the close button is hidden.
     */
    onDismiss?: () => void;
    /**
     * Custom media to override the default status icon.
     * Success and proposition sentiments support 2 status variations: standard checkmark & confetti.
     */
    media?: InfoPromptMedia;
    /**
     * Action link to be displayed below the description
     */
    action?: InfoPromptAction;
    /**
     * Title content for the prompt
     */
    title?: string;
    /**
     * Description content for the prompt (required). Accepts plain text or rich content (ReactNode).
     * If the description contains an interactive element, the `action` prop must not be used simultaneously.
     */
    description: ReactNode;
    className?: string;
    /**
     * Sets the ARIA live region politeness level.
     * - `'polite'` — announced after the current speech (default)
     * - `'assertive'` — interrupts the current speech immediately
     * - `'off'` — disables the live region entirely
     * @default 'polite'
     */
    'aria-live'?: AriaLive;
  };

/**
 * `InfoPrompt` displays important contextual messages to users within a screen.
 * It provides a visually distinct way to communicate information, warnings, errors,
 * or positive feedback with optional actions and dismissal capabilities.
 *
 * Use this component to replace the deprecated `Alert` component (run codemod to migrate: **`npx \@wise/wds-codemods@latest info-prompt`**).
 *
 * Guidance can be found in the [design system](https://docs.wise.design/components/info-prompt).
 */
export const InfoPrompt = ({
  sentiment = 'neutral',
  onDismiss,
  media,
  action,
  title,
  description,
  className,
  'aria-live': ariaLive = 'polite',
  'data-testid': dataTestId,
  ...restProps
}: InfoPromptProps) => {
  const [shouldFire, setShouldFire] = useState<boolean>();
  const announceOnChange = [
    title,
    Children.toArray(description)
      .map((child) =>
        isValidElement<{ children?: ReactNode }>(child) ? child.props.children : child,
      )
      .join(''),
    action?.label,
  ]
    .filter(Boolean)
    .join('|');
  const statusIconSentiment =
    sentiment === 'success'
      ? Sentiment.POSITIVE
      : (sentiment as Exclude<SurfaceSentiment, 'proposition'>);

  const handleTouchStart = () => {
    setShouldFire(true);
  };

  const handleTouchEnd = () => {
    if (shouldFire && action?.href) {
      if (action.target === '_blank') {
        window.top?.open(action.href, '_blank', 'noopener, noreferrer');
      } else {
        window.top?.location.assign(action.href);
      }
    }
    setShouldFire(false);
  };

  const handleTouchMove = () => {
    setShouldFire(false);
  };

  const renderMedia = () => {
    if (media) {
      return <span className="wds-info-prompt__media">{media.asset}</span>;
    }

    if (sentiment === 'proposition') {
      return (
        <span className="wds-info-prompt__media">
          <GiftBox />
        </span>
      );
    }

    return <StatusIcon size={24} sentiment={statusIconSentiment} />;
  };

  // Render content directly in LiveRegion
  return (
    <LiveRegion aria-live={ariaLive} announceOnChange={announceOnChange}>
      <PrimitivePrompt
        sentiment={sentiment}
        media={renderMedia()}
        data-testid={dataTestId}
        className={clsx('wds-info-prompt', className)}
        {...restProps}
        onTouchStart={handleTouchStart}
        onTouchEnd={handleTouchEnd}
        onTouchMove={handleTouchMove}
        onDismiss={onDismiss}
      >
        <div className="wds-info-prompt__content">
          {title && (
            <Body className="wds-info-prompt__title" type={Typography.BODY_LARGE_BOLD} as="span">
              {title}
            </Body>
          )}
          <Body as="span" className="wds-info-prompt__description">
            {description}
          </Body>
          {action && (
            <Link
              href={action.href}
              target={action.target}
              type={Typography.LINK_DEFAULT}
              className="wds-info-prompt__action"
              onClick={action.onClick}
            >
              {action.label}
            </Link>
          )}
        </div>
      </PrimitivePrompt>
    </LiveRegion>
  );
};
