import React, { ReactNode } from 'react';
import cx from 'classnames';

interface BaseTextProps {
  extraClass?: string;
  children: ReactNode;
}

type SupportedTags = 'h1' | 'h2' | 'h3' | 'h4' | 'p' | 'span';

interface TextProps extends BaseTextProps {
  tag: SupportedTags;
}

const GenericText = ({ tag, extraClass, children }: TextProps) => {
  const Tag = tag as keyof JSX.IntrinsicElements;

  return <Tag className={extraClass}>{children}</Tag>;
};


interface HeaderProps extends BaseTextProps {
  size: 'h1' | 'h2' | 'h3' | 'h4';
}

const Headline = ({ size, extraClass, children }: HeaderProps) => {
  switch (size) {
    case 'h1':
      return <GenericText tag="h1" extraClass={cx('o-text__headline o-text__headline--1', extraClass)}>{children}</GenericText>;
    case 'h2':
      return <GenericText tag="h2" extraClass={cx('o-text__headline o-text__headline--2', extraClass)}>{children}</GenericText>;
    case 'h3':
      return <GenericText tag="h3" extraClass={cx('o-text__headline o-text__headline--3', extraClass)}>{children}</GenericText>;
    case 'h4':
      return <GenericText tag="h4" extraClass={cx('o-text__headline o-text__headline--4', extraClass)}>{children}</GenericText>;
    default:
      throw `Unsupported header size ${size}`;
  }
};

const Link = ({ extraClass, children }: BaseTextProps) => (
  <GenericText tag="span" extraClass={cx('o-text__link', extraClass)}>{children}</GenericText>
);

const Button = ({ extraClass, children }: BaseTextProps) => (
  <GenericText tag="span" extraClass={cx('o-text__button', extraClass)}>{children}</GenericText>
);

interface ParapgraphProps extends BaseTextProps {
  secondary?: boolean;
  bold?: boolean;
  size?: 'large' | 'small';
}

const Paragraph = ({ secondary, bold, size, extraClass, children }: ParapgraphProps) => (
  <GenericText tag="p" extraClass={cx('o-text__paragraph', {
    'o-text__paragraph--secondary': secondary,
    'o-text__paragraph--bold': bold,
    'o-text__paragraph--large': size === 'large',
    'o-text__paragraph--small': size === 'small',
  }, extraClass)}>
    {children}
  </GenericText>
);

interface CaptionProps extends BaseTextProps {
  graph?: boolean;
}

const Caption = ({ graph, extraClass, children }: CaptionProps) => (
  <GenericText tag="p" extraClass={cx('o-text__caption', { 'o-text__caption--graph': graph }, extraClass)}>
    {children}
  </GenericText>
);

const Label = ({ extraClass, children }: BaseTextProps) => (
  <GenericText tag="p" extraClass={cx('o-text__label', extraClass)}>{children}</GenericText>
);

const Menu = ({ extraClass, children }: BaseTextProps) => (
  <GenericText tag="p" extraClass={cx('o-text__menu', extraClass)}>{children}</GenericText>
);

export {
  GenericText,
  Headline,
  Link,
  Button,
  Paragraph,
  Caption,
  Label,
  Menu,
};
