import { ReactElement, useState } from 'react';
import { Meta, StoryObj } from '@storybook/react-webpack5';
import { fn } from 'storybook/test';
import { Bank, Star, Suitcase, Briefcase } from '@transferwise/icons';
import {
  createSandboxStory,
  globalScope,
} from '../../../.storybook/components/sandbox/SandboxEditor';
import { lorem10, lorem20 } from '../../test-utils';
import Button from '../../button';
import Title from '../../title';
import { ActionPrompt, type ActionPromptProps } from './ActionPrompt';

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>
  );

const meta: Meta<typeof ActionPrompt> = {
  title: 'Prompts/ActionPrompt',
  component: ActionPrompt,
  tags: ['new'],
  decorators: [withComponentGrid()],
  args: {
    title: 'Action Required',
    description: 'Please complete the following action to continue.',
    action: { label: 'Continue', onClick: fn() },
  },
  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: {
      control: false,
      table: {
        type: {
          summary: 'ActionPromptMedia',
          detail:
            '{ imgSrc?: string; avatar?: { imgSrc?: string; profileName?: string; profileType?: string; asset?: ReactNode; badge?: { flagCode: string } }; aria-label?: string }',
        },
      },
    },
    action: {
      control: false,
      table: {
        type: {
          summary: 'ActionPromptAction',
          detail: '{ label: ReactNode; onClick?: () => void; href?: string; target?: string }',
        },
      },
    },
    actionSecondary: {
      control: false,
      table: {
        type: {
          summary: 'ActionPromptActionSecondary',
          detail: '{ label: ReactNode; onClick?: () => void; href?: string; target?: string }',
        },
      },
    },
  },
};

export default meta;
type Story = StoryObj<typeof ActionPrompt>;

/**
 * Convenience controls for previewing rich markup,
 * not otherwise possible via Storybook
 */
type PreviewStoryArgs = ActionPromptProps & {
  previewMedia: ActionPromptProps['media'];
  previewOnDismiss: boolean;
  previewSecondaryAction: boolean;
};

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

const MEDIA_OPTIONS: Record<string, ActionPromptProps['media']> = {
  undefined,
  'Custom image (no badge)': { imgSrc: '../../wise-card.svg' },
  'Avatar: Profile image': { avatar: { imgSrc: '../../avatar-rectangle-fox.webp' } },
  'Avatar: Business (GB badge)': {
    avatar: { profileType: 'BUSINESS', badge: { flagCode: 'GB' } },
  },
  'Avatar: Personal (EU badge)': {
    avatar: { profileType: 'PERSONAL', badge: { flagCode: 'EU' } },
  },
  'Avatar: Icon (Bank)': { avatar: { asset: <Bank /> } },
  'Avatar: Icon (Star)': { avatar: { asset: <Star /> } },
  'Avatar: Icon (Suitcase)': { avatar: { asset: <Suitcase /> } },
  'Avatar: Icon (Briefcase)': { avatar: { asset: <Briefcase /> } },
  'Avatar: Initials': { avatar: { profileName: 'John Doe' } },
};

const previewArgTypes = {
  previewMedia: {
    name: 'Preview with `media`',
    control: 'select',
    options: [
      'undefined',
      'Custom image (no badge)',
      'Avatar: Profile image',
      'Avatar: Business (GB badge)',
      'Avatar: Personal (EU badge)',
      'Avatar: Icon (Bank)',
      'Avatar: Icon (Star)',
      'Avatar: Icon (Suitcase)',
      'Avatar: Icon (Briefcase)',
      'Avatar: Initials',
    ],
    mapping: MEDIA_OPTIONS,
    table: previewArgGroup,
  },
  previewOnDismiss: {
    name: 'Preview with `onDismiss`',
    control: 'boolean',
    table: previewArgGroup,
  },
  previewSecondaryAction: {
    name: 'Preview with `actionSecondary`',
    control: 'boolean',
    table: previewArgGroup,
  },
} as const;

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

  return [
    props,
    {
      media: previewMedia,
      onDismiss: previewOnDismiss ? fn() : undefined,
      actionSecondary: previewSecondaryAction ? { label: 'Cancel', onClick: fn() } : undefined,
    },
  ];
};

export const Playground: StoryObj<PreviewStoryArgs> = {
  argTypes: {
    sentiment: {
      control: 'radio',
      options: ['success', 'negative', 'neutral', 'warning', 'proposition'],
    },
    ...previewArgTypes,
  },
  args: {
    previewMedia: { avatar: undefined },
    previewOnDismiss: true,
    previewSecondaryAction: true,
  },
  render: (args: PreviewStoryArgs) => {
    const [props, previewProps] = getPropsForPreview(args);
    return <ActionPrompt {...props} {...previewProps} />;
  },
};

export const Sandbox = createSandboxStory({
  code: `const App = () => {
  const [dismissed, setDismissed] = React.useState(false);

  if (dismissed) {
    return (
      <Button v2 size="md" onClick={() => setDismissed(false)}>
        Show prompt again
      </Button>
    );
  }

  return (
    <ActionPrompt
      sentiment="neutral"
      title="Action Required"
      description="Please complete the following action to continue."
      media={{ avatar: { asset: <Bank /> } }}
      action={{ label: 'Continue', onClick: () => console.log('action clicked') }}
      actionSecondary={{ label: 'Cancel', onClick: () => console.log('cancel clicked') }}
      onDismiss={() => setDismissed(true)}
    />
  );
};`,
  scope: globalScope,
});

/**
 * ActionPrompt supports multiple sentiments to communicate different types of messages:
 * - `neutral` (default): General prompts
 * - `success`: Success confirmations
 * - `negative`: Error or critical actions
 * - `warning`: Warning messages
 * - `proposition`: Promotional or feature prompts
 */
export const Sentiments: Story = {
  render: (args) => (
    <>
      {(['success', 'warning', 'negative', 'neutral', 'proposition'] as const).map((sentiment) => (
        <ActionPrompt
          key={sentiment}
          sentiment={sentiment}
          title={`${sentiment.charAt(0).toUpperCase() + sentiment.slice(1)} Action`}
          description={lorem10}
          action={{ label: 'Primary', onClick: fn() }}
          actionSecondary={{ label: 'Secondary', onClick: fn() }}
        />
      ))}
    </>
  ),
};

/**
 * ActionPrompt can have just a primary action, or both primary and secondary actions.
 */
export const Actions: Story = {
  render: () => (
    <>
      <ActionPrompt
        sentiment="proposition"
        title="Primary action only"
        description="This prompt has only one action button."
        action={{ label: 'Get started', onClick: fn() }}
      />
      <ActionPrompt
        sentiment="warning"
        title="Primary and secondary actions"
        description="This prompt has both action buttons."
        action={{ label: 'Confirm', onClick: fn() }}
        actionSecondary={{ label: 'Cancel', onClick: fn() }}
      />
    </>
  ),
};

/**
 * ActionPrompt 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 images, avatars with images, avatars with initials,
 * avatars with custom icons, or avatars with profile types and badges.
 */
export const MediaTypes: Story = {
  render: () => {
    return (
      <>
        <Title type="title-body">Default</Title>
        <ActionPrompt
          sentiment="success"
          title="Default status icon"
          description="When no media is provided, the sentiment's default status icon is displayed."
          action={{ label: 'Continue', onClick: fn() }}
        />

        <Title type="title-body">Icon Overrides</Title>
        <ActionPrompt
          sentiment="neutral"
          title="Custom image"
          description={lorem10}
          media={{ imgSrc: '../../wise-card.svg' }}
          action={{ label: 'View card', onClick: fn() }}
        />
        <ActionPrompt
          sentiment="neutral"
          title="Avatar with image"
          description={lorem10}
          media={{ avatar: { imgSrc: '../../avatar-rectangle-fox.webp' } }}
          action={{ label: 'View profile', onClick: fn() }}
        />
        <ActionPrompt
          sentiment="success"
          title="Avatar with initials"
          description={lorem10}
          media={{ avatar: { profileName: 'John Doe' } }}
          action={{ label: 'Send invite', onClick: fn() }}
        />
        <ActionPrompt
          sentiment="warning"
          title="Avatar with custom icon"
          description={lorem10}
          media={{ avatar: { asset: <Bank /> } }}
          action={{ label: 'Connect bank', onClick: fn() }}
        />
        <ActionPrompt
          sentiment="proposition"
          title="Business profile with badge"
          description={lorem10}
          media={{ avatar: { profileType: 'BUSINESS', badge: { flagCode: 'GB' } } }}
          action={{ label: 'Open account', onClick: fn() }}
        />
        <ActionPrompt
          sentiment="negative"
          title="Personal profile with badge"
          description={lorem10}
          media={{ avatar: { profileType: 'PERSONAL', badge: { flagCode: 'EU' } } }}
          action={{ label: 'Verify', onClick: fn() }}
        />
      </>
    );
  },
};

/**
 * 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: Story = {
  render: (args) => {
    const [showPrompt, setShowPrompt] = useState(true);

    return (
      <>
        {showPrompt ? (
          <ActionPrompt
            sentiment="proposition"
            title="Special offer"
            description="Get 50% off your next transfer!"
            action={{ label: 'Claim now', onClick: fn() }}
            onDismiss={() => setShowPrompt(false)}
          />
        ) : (
          <Button v2 onClick={() => setShowPrompt(true)}>
            Show prompt again
          </Button>
        )}
      </>
    );
  },
};

/**
 * 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://docs.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: Story = {
  parameters: {
    docs: {
      canvas: {
        sourceState: 'hidden',
      },
    },
  },
  args: {
    title: lorem10,
    description: lorem20,
    sentiment: 'success',
    action: { label: 'View details', onClick: fn() },
    onDismiss: () => {},
  },
};
