import { Illustration, Assets, IllustrationNames } from '@wise/art';
import { clsx } from 'clsx';
import { ReactNode, useEffect, useState, MouseEvent } from 'react';

import Body from '../body';
import { Typography } from '../common';
import { CloseButton } from '../common/closeButton';
import Link from '../link';
import { Action, ActionOptions } from '../common/action/Action';

// WARNING: Changing this will cause nudges to reappear wherever persist nudge is used and privacy team will need to be updated too
export const STORAGE_NAME = 'dismissedNudges';

const getLocalStorage = (): string[] => {
  try {
    const storageItem = localStorage.getItem(STORAGE_NAME);

    if (storageItem) {
      const storage: unknown = JSON.parse(storageItem);

      if (Array.isArray(storage)) {
        return storage.map((item) => String(item));
      }
    }
    // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty
  } catch (error) {}

  return [];
};

type MediaNameType =
  | `${Assets.GLOBE}`
  | `${Assets.LOCK}`
  | `${Assets.WALLET}`
  | `${Assets.GEAR}`
  | `${Assets.INVITE_LETTER}`
  | `${Assets.PERSONAL_CARD}`
  | `${Assets.BUSINESS_CARD}`
  | `${Assets.HEART}`
  | `${Assets.MULTI_CURRENCY}`
  | `${Assets.SHOPPING_BAG}`;

type BaseProps = {
  /** @deprecated use `mediaName` property instead */
  media?: ReactNode;
  /** Media name  */
  mediaName?: MediaNameType;
  title: ReactNode;
  link?: ReactNode;
  href?: string;
  onClick?: (event?: MouseEvent<HTMLSpanElement>) => void;
  /** Fired when the user clicks on close button */
  onDismiss?: () => void;
  /** An optional call to action to sit under the main body of the nudge. If your label is short, use aria-label to provide more context */
  action?: ActionOptions;
  className?: string;
};

export interface OptionalId extends BaseProps {
  id?: string;
  persistDismissal?: false;
  isPreviouslyDismissed?: undefined;
}

export interface RequiredPersistProps extends BaseProps {
  /** This ID should be completely unique to the page and feature as it uses a shared array which could conflict with other nudges in Wise */
  id: string;
  /** Use persist dismissal to keep the nudge dismissed using the browser's localStorage */
  persistDismissal: true;
  /**
   * Fired on mount for determining if nudge has been dismissed before
   *
   * @param {boolean}  value - set to true if dismissed previously
   */
  isPreviouslyDismissed?: (value: boolean) => void;
}

export type Props = OptionalId | RequiredPersistProps;

const Nudge = ({
  media,
  mediaName,
  title,
  link,
  href,
  onClick,
  onDismiss,
  persistDismissal,
  isPreviouslyDismissed,
  id,
  className,
  action,
}: Props) => {
  const [isDismissed, setIsDismissed] = useState(false);
  const [isMounted, setIsMounted] = useState(false);

  const handleOnDismiss = () => {
    const dismissedNudgesStorage = getLocalStorage();

    if (persistDismissal && id) {
      try {
        localStorage.setItem(STORAGE_NAME, JSON.stringify([...dismissedNudgesStorage, id]));
        // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty
      } catch (error) {}

      setIsDismissed(true);
    }

    if (onDismiss) {
      onDismiss();
    }
  };

  useEffect(() => {
    if (persistDismissal && id) {
      const dismissedNudgesStorage = getLocalStorage();
      let isDismissed = false;

      if (dismissedNudgesStorage?.find((item) => item === id)) {
        setIsDismissed(true);
        isDismissed = true;
      }

      if (isPreviouslyDismissed) {
        isPreviouslyDismissed(isDismissed);
      }
    }

    setIsMounted(true);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [id, persistDismissal]);

  if (persistDismissal && (isDismissed || !isMounted)) {
    return null;
  }

  return (
    <div className={clsx('wds-nudge', className)} id={id}>
      {!!mediaName && (
        <div className="wds-nudge-media">
          <Illustration
            name={mediaName as IllustrationNames}
            className={clsx(`wds-nudge-media-${mediaName}`)}
            size="small"
            disablePadding
            alt=""
          />
        </div>
      )}
      <div className="wds-nudge-container">
        <div className="wds-nudge-content">
          <Body type={Typography.BODY_LARGE} className={clsx('wds-nudge-body')}>
            {title}
          </Body>
          {link && (
            <Link
              href={href}
              type={Typography.LINK_LARGE}
              className="wds-nudge-link"
              onClick={onClick}
            >
              {link}
            </Link>
          )}
          {action && <Action action={action} className="m-t-1" />}
        </div>
        {onDismiss || persistDismissal ? (
          <CloseButton className="wds-nudge-control" size="sm" onClick={handleOnDismiss} />
        ) : null}
      </div>
    </div>
  );
};

export default Nudge;
