import { Link } from '@tanstack/react-router';
import clsx from 'clsx';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';

import SvgIcon from 'pl-fe/components/ui/svg-icon';

const sizes = {
  md: 'p-4 sm:rounded-xl',
  lg: 'p-4 sm:p-6 sm:rounded-xl',
  xl: 'p-4 sm:p-10 sm:rounded-3xl',
};

const messages = defineMessages({
  back: { id: 'card.back.label', defaultMessage: 'Back' },
});

type CardSizes = keyof typeof sizes

interface ICard extends Pick<React.HTMLAttributes<HTMLDivElement>, 'role' | 'aria-label'> {
  /** The type of card. */
  variant?: 'default' | 'rounded' | 'slim';
  /** Card size preset. */
  size?: CardSizes;
  /** Extra classnames for the <div> element. */
  className?: string;
  /** Elements inside the card. */
  children: React.ReactNode;
  tabIndex?: number;
}

/** An opaque backdrop to hold a collection of related elements. */
const Card = React.forwardRef<HTMLDivElement, ICard>(({ children, variant = 'default', size = 'md', className, ...filteredProps }, ref): JSX.Element => (
  <div
    ref={ref}
    {...filteredProps}
    className={clsx({
      'bg-white dark:bg-primary-900 black:bg-black text-gray-900 dark:text-gray-100 shadow-lg dark:shadow-none': variant === 'rounded',
      [sizes[size]]: variant === 'rounded',
      'py-4': variant === 'slim',
      'black:rounded-none': size !== 'xl',
    }, className)}
  >
    {children}
  </div>
));

interface ICardHeader {
  backHref?: string;
  onBackClick?: (event: React.MouseEvent) => void;
  className?: string;
  children?: React.ReactNode;
}

/**
 * Card header container with back button.
 * Typically holds a CardTitle.
 */
const CardHeader: React.FC<ICardHeader> = ({ className, children, backHref, onBackClick }): JSX.Element => {
  const intl = useIntl();

  const renderBackButton = () => {
    if (!backHref && !onBackClick) {
      return null;
    }

    const Comp: React.ElementType = backHref ? Link : 'button';
    const backAttributes = backHref ? { to: backHref } : { onClick: onBackClick };

    return (
      <Comp {...backAttributes} className='⁂-card-header__button' aria-label={intl.formatMessage(messages.back)}>
        <SvgIcon src={require('@phosphor-icons/core/regular/arrow-left.svg')} />
        <span className='⁂-card-header__button__label' data-testid='back-button'>{intl.formatMessage(messages.back)}</span>
      </Comp>
    );
  };

  return (
    <div className={clsx('⁂-card-header', className)}>
      {renderBackButton()}

      {children}
    </div>
  );
};

interface ICardTitle {
  title: React.ReactNode;
  truncate?: boolean;
}

/** A card's title. */
const CardTitle: React.FC<ICardTitle> = ({ title, truncate = true }): JSX.Element => (
  <h1 className='⁂-card-title' data-testid='card-title'>{title}</h1>
);

interface ICardBody {
  /** Classnames for the <div> element. */
  className?: string;
  /** Children to appear inside the card. */
  children: React.ReactNode;
}

/** A card's body. */
const CardBody: React.FC<ICardBody> = ({ className, children }): JSX.Element => (
  <div data-testid='card-body' className={className}>{children}</div>
);

export {
  type CardSizes,
  Card as default,
  Card,
  CardHeader,
  CardTitle,
  CardBody,
};
