import type { ReactElement } from 'react';
import { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react-webpack5';
import { action } from 'storybook/actions';
import { Confetti, GiftBox, Star, Travel, Briefcase, Plane } from '@transferwise/icons';
import { lorem10, lorem20 } from '../../test-utils';
import Button from '../../button';
import Title from '../../title';
import { InfoPrompt, InfoPromptProps, InfoPromptMedia } from './InfoPrompt';

const withComponentGrid =
  ({ maxWidth = 'auto', gap = '1rem' } = {}) =>
  (Story: () => ReactElement) => (
    <div
      style={{
        width: '100%',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'flex-start',
        alignItems: 'flex-start',
        alignContent: 'flex-start',
        gap,
        maxWidth,
      }}
    >
      <Story />
    </div>
  );

export default {
  title: 'Prompts/InfoPrompt',
  component: InfoPrompt,
  tags: ['new'],
  decorators: [withComponentGrid()],
  args: {
    description: 'Your payment is being processed.',
  },
  argTypes: {
    sentiment: {
      control: 'select',
      options: ['success', 'negative', 'neutral', 'warning', 'proposition'],
    },
    title: {
      control: 'text',
      table: {
        type: { summary: 'ReactNode' },
      },
    },
    description: {
      control: 'text',
      table: {
        type: { summary: 'ReactNode' },
      },
    },
    media: {
      table: {
        type: { summary: 'InfoPromptMedia', detail: '{ asset: ReactNode }' },
      },
    },
    action: {
      table: {
        type: {
          summary: 'InfoPromptAction',
          detail: '{ label: string; href?: string; target?: string; onClick?: () => void }',
        },
      },
    },
  },
} satisfies Meta<InfoPromptProps>;

/**
 * Convenience controls for previewing rich markup,
 * not otherwise possible via Storybook
 */
type PreviewStoryArgs = InfoPromptProps & {
  previewMedia: InfoPromptMedia | undefined;
  previewOnDismiss: boolean;
  previewAction: boolean;
};

const previewArgGroup = {
  category: 'Storybook Preview options',
  type: {
    summary: undefined,
  },
};

const MEDIA_OPTIONS: Record<string, { asset: ReactElement } | undefined> = {
  undefined,
  star: { asset: <Star title="Starred" /> },
  confetti: { asset: <Confetti size={24} title="Celebration" /> },
  giftbox: { asset: <GiftBox title="Gift" /> },
  travel: { asset: <Travel title="Travel" /> },
  briefcase: { asset: <Briefcase title="Business" /> },
  plane: { asset: <Plane title="Travel" /> },
};

const previewArgTypes = {
  previewMedia: {
    name: 'Preview with `media`',
    control: 'select',
    options: ['undefined', 'star', 'confetti', 'giftbox', 'travel', 'briefcase', 'plane'],
    mapping: MEDIA_OPTIONS,
    table: previewArgGroup,
  },
  previewOnDismiss: {
    name: 'Preview with `onDismiss`',
    control: 'boolean',
    table: previewArgGroup,
  },
  previewAction: {
    name: 'Preview with `action`',
    control: 'boolean',
    table: previewArgGroup,
  },
} as const;

const getPropsForPreview = (
  args: PreviewStoryArgs,
): [InfoPromptProps, Partial<InfoPromptProps>] => {
  const { previewMedia, previewOnDismiss, previewAction, ...props } = args;

  return [
    props,
    {
      media: previewMedia,
      onDismiss: previewOnDismiss ? action('onDismiss') : undefined,
      action: previewAction
        ? { label: 'Learn more', onClick: action('action.onClick') }
        : undefined,
    },
  ];
};

export const Playground: StoryObj<PreviewStoryArgs> = {
  argTypes: {
    sentiment: {
      control: 'radio',
      options: ['success', 'negative', 'neutral', 'warning', 'proposition'],
    },
    ...previewArgTypes,
  },
  args: {
    title: 'Payment successful',
    description: 'Your payment is being processed.',
    previewMedia: { asset: <Star title="Starred" /> },
    previewOnDismiss: true,
    previewAction: true,
  },
  render: (args: PreviewStoryArgs) => {
    const [props, previewProps] = getPropsForPreview(args);
    return <InfoPrompt {...props} {...previewProps} />;
  },
};

/**
 * InfoPrompt supports multiple sentiments to communicate different types of messages:
 * - `neutral` (default): General information
 * - `success`: Success messages
 * - `negative`: Error messages
 * - `warning`: Warning messages
 * - `proposition`: Promotional content (uses GiftBox icon by default)
 */
export const Sentiments: StoryObj<InfoPromptProps> = {
  render: (args: InfoPromptProps) => (
    <>
      <InfoPrompt {...args} sentiment="neutral" description="This is a neutral message." />
      <InfoPrompt {...args} sentiment="success" description="Your payment was successful!" />
      <InfoPrompt {...args} sentiment="negative" description="Something went wrong." />
      <InfoPrompt {...args} sentiment="warning" description="Please review your details." />
      <InfoPrompt {...args} sentiment="proposition" description="Check out our new features!" />
    </>
  ),
};

/**
 * InfoPrompt can include both a title and description for more detailed messaging.
 */
export const WithTitle: StoryObj<InfoPromptProps> = {
  render: (args: InfoPromptProps) => (
    <>
      <InfoPrompt
        {...args}
        sentiment="success"
        title="Payment Successful"
        description="Your money is on its way to the recipient."
      />
      <InfoPrompt
        {...args}
        sentiment="warning"
        title="Payment Delayed"
        description="Payments sent today might not arrive in time for the holidays."
      />
      <InfoPrompt
        {...args}
        sentiment="negative"
        title="Payment Failed"
        description="We couldn't process your payment. Please try again."
      />
    </>
  ),
};

/**
 * Use the `action` prop to add a clickable link below the message.
 * Actions can have an `href` for navigation or an `onClick` for custom behavior.
 */
export const WithAction: StoryObj<InfoPromptProps> = {
  render: (args: InfoPromptProps) => (
    <>
      <InfoPrompt
        {...args}
        sentiment="neutral"
        description="New feature available"
        action={{ label: 'Learn more', href: '/features', target: '_blank' }}
      />
      <InfoPrompt
        {...args}
        sentiment="warning"
        title="Action Required"
        description="Please verify your identity to continue."
        action={{ label: 'Verify now', onClick: action('verify') }}
      />
      <InfoPrompt
        {...args}
        sentiment="proposition"
        title="Special Offer"
        description="Get 50% off your next transfer!"
        action={{ label: 'Claim offer', onClick: action('claim') }}
      />
    </>
  ),
};

/**
 * When `onDismiss` is provided, a close button appears allowing users to dismiss the prompt.
 * Note: The component itself is not automatically removed - you must handle state management.
 */
export const Dismissible: StoryObj<InfoPromptProps> = {
  render: function Render() {
    const [showPrompt, setShowPrompt] = useState(true);

    return (
      <>
        {showPrompt ? (
          <InfoPrompt
            sentiment="success"
            title="Payment successful"
            description="Your payment was successful."
            onDismiss={() => setShowPrompt(false)}
          />
        ) : (
          <Button v2 onClick={() => setShowPrompt(true)}>
            Show prompt again
          </Button>
        )}
      </>
    );
  },
};

/**
 * InfoPrompt supports various media types to enhance visual communication.
 *
 * **Default**: Each sentiment has a default status icon that appears when no media is provided.
 *
 * **Icon Overrides**: Replace default icons with custom icons to match the prompt's visual language to its content.
 * Success and proposition sentiments support both standard checkmark and confetti variations.
 */
export const MediaTypes: StoryObj<InfoPromptProps> = {
  render: (args) => (
    <>
      <Title type="title-body">Default</Title>
      <InfoPrompt
        sentiment="success"
        description="When no media is provided, the sentiment's default status icon is displayed."
      />

      <Title type="title-body">Icon Overrides</Title>
      <InfoPrompt
        sentiment="success"
        description="Saved to favorites!"
        media={{ asset: <Star title="Starred" /> }}
      />
      <InfoPrompt
        sentiment="success"
        title="Congratulations!"
        description="You've completed all the steps."
        media={{ asset: <Confetti size={24} title="Celebration" /> }}
      />
      <InfoPrompt
        sentiment="proposition"
        title="Special offer"
        description="New ways to send money with Wise!"
        media={{ asset: <GiftBox title="Gift" /> }}
      />
      <InfoPrompt
        sentiment="success"
        description="Your travel account is ready!"
        media={{ asset: <Travel title="Travel" /> }}
      />
      <InfoPrompt
        sentiment="warning"
        title="Business travel"
        description="Book your business trip with Wise."
        media={{ asset: <Briefcase title="Business" /> }}
      />
      <InfoPrompt
        sentiment="neutral"
        description="Your flight is scheduled."
        media={{ asset: <Plane title="Flight" /> }}
      />
    </>
  ),
};

/**
 * While the component itself will stretch to the full available width, the text container will be
 * capped at `480px` to ensure optimal readability.
 *
 * [Visit wise.design](https://wise.design/components/info-prompt#writing-an-info-prompt) for guidance on writing effective prompt messages that are concise and easy to understand.
 */
export const ParagraphWidth: StoryObj<PreviewStoryArgs> = {
  parameters: {
    docs: {
      canvas: {
        sourceState: 'hidden',
      },
    },
  },
  args: {
    title: lorem10,
    description: lorem20,
    sentiment: 'success',
    onDismiss: () => {},
  },
};
