import React, { useState } from 'react';
import { Meta, StoryObj } from '@storybook/react-webpack5';
import { action } from 'storybook/actions';
import { ClockBorderless } from '@transferwise/icons';
import { createSandboxStory } from '../../.storybook/components/sandbox/SandboxEditor';

import { lorem40 } from '../test-utils';
import { Sentiment, Status } from '../common';
import { Button, Field, SelectInput } from '..';
import Alert, { AlertArrowPosition, type AlertProps as FullAlertProps } from './Alert';

/**
 * > **DEPRECATED** Use [InfoPrompt](?path=/docs/prompts-infoprompt--docs). Run codemod to migrate: **`npx @wise/wds-codemods@latest info-prompt`**.
 */
export default {
  component: Alert,
  title: 'Prompts/Alert',
  tags: ['deprecated'],
  args: {
    type: Sentiment.POSITIVE,
    message:
      'Payments sent to your bank details **today** might not arrive in time for the holidays.',
  },
  argTypes: {
    arrow: {
      name: 'arrow (deprecated)',
      type: {
        name: 'enum',
        value: Object.keys(AlertArrowPosition),
      },
    },
    type: {
      type: {
        name: 'enum',
        value: [
          Sentiment.POSITIVE,
          Sentiment.NEGATIVE,
          Sentiment.NEUTRAL,
          Sentiment.WARNING,
          Sentiment.PENDING,
          Status.PENDING,
        ],
      },
    },
  },
} satisfies Meta<typeof Alert>;

type Story = StoryObj<typeof Alert>;

export const Basic: Story = {};

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

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

  return (
    <Alert
      action={{
        'aria-label': 'Learn more',
        text: 'Learn more',
        href: '#',
      }}
      message="Payments sent to your bank details **today** might not arrive in time for the holidays."
      onDismiss={() => setDismissed(true)}
      type="positive"
    />
  );
};`,
  scope: { Alert, Button, React },
});

export const Variants: Story = {
  render: ({ message }) => {
    const variants = [
      { type: Sentiment.POSITIVE, title: 'Positive Title' },
      { type: Sentiment.NEGATIVE, title: 'Negative Title' },
      { type: Sentiment.NEUTRAL, title: 'Neutral Title' },
      { type: Sentiment.WARNING, title: 'Warning Title' },
      { type: Sentiment.PENDING, title: 'Pending Sentiment Title' },
      { type: Status.PENDING, title: 'Pending Status Title' },
    ];

    return (
      <>
        {variants.map((variant) => (
          <Alert
            key={variant.type}
            type={variant.type as AlertProps['type']}
            title={variant.title}
            message={message}
            action={
              variant.type === Sentiment.NEUTRAL
                ? { href: '#', text: 'Read more' }
                : { onClick: action('alert action clicked'), text: 'Open' }
            }
            onDismiss={variant.type === Sentiment.NEUTRAL ? action('alert dismissed') : undefined}
          />
        ))}
      </>
    );
  },
  args: {
    message: 'This message can be changed using controls',
  },
  parameters: {
    controls: { exclude: /^(?!message$).*/ },
  },
  argTypes: {
    message: { control: 'text' },
  },
};

export const WithLinkAction: Story = {
  args: {
    action: {
      href: '/',
      text: 'Read more',
    },
    onDismiss: () => {},
  },
};

export const WithButtonAction: Story = {
  args: {
    action: {
      onClick: action('alert action clicked'),
      text: 'Open',
    },
    onDismiss: () => {},
  },
};

export const WithArrow: Story = {
  args: {
    arrow: AlertArrowPosition.TOP_LEFT,
    onDismiss: () => {},
  },
};

const CustomIcon = () => {
  return (
    <div
      style={{
        width: '100%',
        height: '100%',
        color: '#ffffff',
        backgroundColor: '#454745',
        display: 'flex',
        alignItems: 'center',
        borderRadius: '50%',
        justifyContent: 'center',
      }}
    >
      <ClockBorderless size="24" />
    </div>
  );
};

export const WithCustomIcon: Story = {
  args: {
    icon: <CustomIcon />,
    onDismiss: () => {},
  },
};

export const WithTitleAndButtonAction: Story = {
  args: {
    type: Sentiment.NEUTRAL,
    title: 'We’re reviewing your information.',
    message:
      'Payments sent to your bank details **today** might not arrive in time for the holidays.',
    onDismiss: () => {},
    action: {
      onClick: action('alert action clicked'),
      text: 'Open',
    },
  },
};
export const WithTitleAndButtonActionAndLongBody: Story = {
  args: {
    type: Sentiment.NEUTRAL,
    title: 'We’re reviewing your information.',
    message: lorem40,
    onDismiss: () => {},
    action: {
      onClick: action('alert action clicked'),
      text: 'Open',
    },
  },
};

export const WithTitleAndLinkActionAndLongBody: Story = {
  args: {
    type: Sentiment.NEUTRAL,
    title: 'We’re reviewing your information.',
    message: lorem40,
    onDismiss: () => {},
    action: {
      href: '/',
      text: 'Open',
    },
  },
};

/**
 * For ARIA live region to function correctly with screen readers (SR),
 * the container with an appropriate ARIA role (in the case of this
 * component, it's `status` or `alert`) must be rendered first.
 * Once present in the accessibility tree (AT), its dynamic contents
 * will be announced correctly.
 *
 * It's not a problem if your page includes an Alert that is initially
 * visible at the very first render, but if it appears as a result of
 * user interaction or is async, e.g. BE-driven, then the screen reader
 * might not announce it correctly. It becomes even more tricky if an
 * Alert is triggerred by a component that causes refocusing or introduces
 * many modifications to the AT, such as MoneyInput, for example, as that
 * entirely hijacks screen-reader's attention and prevents it from
 * announcing live region changes.
 *
 * In order for this to work, we've introduced a simple mechanism which
 * overcomes all of the above:
 * 1. On the component mount, we render the live region wrapper.
 * 2. We also render the actual Alert but set `aria-hidden` on it.
 * 3. After 175ms, which has been confirmed as sufficient delay for
 * the SRs to become responsive after trigger's activity, we remove the
 * `aria-hidden` attribute,  which, in turn, initiates the announcements.
 *
 * **NB:** While this approach has no visual side-effects (e.g. layout
 * shift), it makes the Alert hidden from the assistive tech for 175ms,
 * during which all nested [focusable components such as links and buttons
 * are disabled](https://dequeuniversity.com/rules/axe/4.10/aria-hidden-focus?application=axeAPI).
 * It's our belief that such short pause between announcements is
 * negligible for the user.
 */
export const DynamicRender: Story = {
  render: function Render(args) {
    const [isOneActive, setIsOneActive] = useState(false);
    const [isTwoActive, setIsTwoActive] = useState(false);
    const [value, setValue] = useState<string>();

    return (
      <>
        <Button v2 onClick={() => setIsOneActive(true)}>
          Trigger Alert
        </Button>

        <Field label="Select `two` to triger Alert" className="m-t-3">
          <SelectInput
            items={[
              { type: 'option', value: 'one' },
              { type: 'option', value: 'two' },
            ]}
            onChange={setValue}
            onClose={() => setIsTwoActive(value === 'two')}
          />
        </Field>

        {isOneActive && <Alert {...args}>This Alert has a simple trigger.</Alert>}
        {isTwoActive && (
          <Alert {...args} type={Sentiment.WARNING}>
            This Alert has a complex trigger.
          </Alert>
        )}
      </>
    );
  },
  args: {
    onDismiss: () => {},
    action: {
      href: '/',
      text: 'Open',
    },
  },
  parameters: {
    docs: {
      source: {
        code: `
function MyComponent(alertProps) {
  const [isOneActive, setIsOneActive] = useState(false);
  const [isTwoActive, setIsTwoActive] = useState(false);
  const [value, setValue] = useState<string>();

  return (
    <>
      <Button v2 onClick={() => setIsOneActive(true)}>
        Trigger Alert
      </Button>

      <Field label="Select \`two\` to triger Alert" className="m-t-3">
        <SelectInput
          items={[
            { type: 'option', value: 'one' },
            { type: 'option', value: 'two' },
          ]}
          onChange={setValue}
          onClose={() => setIsTwoActive(value === 'two')}
        />
      </Field>
      
      {isOneActive && (
        <Alert message="This Alert has a simple trigger" {...alertProps} />
      )}
      {isTwoActive && (
        <Alert message="This Alert has a complex trigger." type={Sentiment.WARNING} {...alertProps} />
      )}
    </>
  );
}`,
      },
    },
  },
};

const SENTIMENT = [
  Sentiment.POSITIVE,
  Sentiment.NEGATIVE,
  Sentiment.NEUTRAL,
  Sentiment.WARNING,
] as const;
type AlertProps = Omit<FullAlertProps, 'type'> & { type: (typeof SENTIMENT)[number] };
const getAlerts = () => {
  const length = Math.ceil(2 + Math.random() * 3);

  return Array.from({ length }, (_, index) => {
    const type = SENTIMENT[Math.floor(Math.random() * SENTIMENT.length)];

    return {
      type,
      title: `Title ${index + 1}`,
      children: `This is a ${type} content`,
    };
  });
};

/**
 * Sometimes, especially when dealing with Backend for Frontend (BFF),
 * it's not just about conditional rendering but also the fact that
 * you don't know how many `Alert`s you'll need to render.
 *
 * If you have to inject multiple Alerts simultaneously into the page,
 * please note that we currently have no means of guaranteeing the order
 * in  which they screen reader will read them out.
 */
export const MultipleDynamicAlerts: Story = {
  render: function Render() {
    const [isActive, setIsActive] = useState(false);
    const [alerts, setAlerts] = useState<AlertProps[]>([]);

    return (
      <>
        <Button
          htmlType="button"
          onClick={() => {
            setAlerts(isActive ? [] : getAlerts());
            setIsActive((current) => !current);
          }}
        >
          Generate dynamic alerts
        </Button>

        {alerts.map((props) => (
          <Alert key={props.title} {...props} className="m-t-3" />
        ))}
      </>
    );
  },
  parameters: {
    docs: {
      source: {
        code: `
function Render() {
  const [isActive, setIsActive] = useState(false);
  const [alerts, setAlerts] = useState<AlertProps[]>([]);

  return (
    <>
      <Button
        htmlType="button"
        onClick={() => {
          setAlerts(isActive ? [] : getAlerts());
          setIsActive((current) => !current);
        }}
      >
        Generate dynamic alerts
      </Button>

      {alerts.map(props => (
        <Alert 
          key={props.title} 
          {...props} 
          className="m-t-3" 
        />
      ))}
    </>
  );
},`,
      },
    },
  },
};
