import { css } from '@tesseract-design/css-utils';

export enum TextControlSize {
  SMALL = 'small',
  MEDIUM = 'medium',
  LARGE = 'large',
}

export enum TextControlStyle {
  DEFAULT = 'default',
  ALTERNATE = 'alternate',
}

export const MIN_HEIGHTS: Record<TextControlSize, string> = {
  [TextControlSize.SMALL]: '2.5rem',
  [TextControlSize.MEDIUM]: '3rem',
  [TextControlSize.LARGE]: '4rem',
};

const LABEL_VERTICAL_PADDING_SIZES: Record<TextControlSize, string> = {
  [TextControlSize.SMALL]: '0.125rem',
  [TextControlSize.MEDIUM]: '0.25rem',
  [TextControlSize.LARGE]: '0.375rem',
};

const INPUT_FONT_SIZES: Record<TextControlSize, string> = {
  [TextControlSize.SMALL]: '0.75em',
  [TextControlSize.MEDIUM]: '0.85em',
  [TextControlSize.LARGE]: '1em',
};

const SECONDARY_TEXT_SIZES: Record<TextControlSize, string> = {
  [TextControlSize.SMALL]: '0.6em',
  [TextControlSize.MEDIUM]: '0.725em',
  [TextControlSize.LARGE]: '0.85em',
};

const MULTILINE_VERTICAL_PADDING_FACTORS: Record<TextControlSize, string> = {
  [TextControlSize.SMALL]: '1.25',
  [TextControlSize.MEDIUM]: '1.2',
  [TextControlSize.LARGE]: '1.45',
};

const ALTERNATE_VERTICAL_PADDING_FACTORS: Record<TextControlSize, string> = {
  [TextControlSize.SMALL]: '1.75',
  [TextControlSize.MEDIUM]: '1.35',
  [TextControlSize.LARGE]: '1.25',
};

export type TextControlBaseArgs = {
  block: boolean,
  style: TextControlStyle,
  border: boolean,
  indicator: boolean,
  size: TextControlSize,
  resizable: boolean,
  predefinedValues: boolean,
}

export const Root = ({
  block,
}: TextControlBaseArgs): string => css.cx(
  css`
    vertical-align: middle;
    position: relative;
    border-radius: 0.25rem;
    font-family: var(--font-family-base, sans-serif);
    max-width: 100%;
    &:focus-within {
      --color-accent: var(--color-hover, red);
    }
    & > span {
      border-color: var(--color-accent, blue);
      box-sizing: border-box;
      display: inline-block;
      border-width: 0.125rem;
      border-style: solid;
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border-radius: inherit;
      z-index: 2;
      pointer-events: none;
      transition-property: border-color;
    }
    & > span::before {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      content: '';
      border-radius: 0.125rem;
      opacity: 0.5;
      pointer-events: none;
      box-shadow: 0 0 0 0 var(--color-accent, blue);
      transition-property: box-shadow;
      transition-duration: 150ms;
      transition-timing-function: linear;
    }
    &:focus-within > span::before {
      box-shadow: 0 0 0 0.375rem var(--color-accent, blue);
    }
  `,
  css.dynamic({
    display: block ? 'block' : 'inline-block',
  }),
);

export const LabelWrapper = ({
  style,
  border,
  indicator,
  size,
}: TextControlBaseArgs): string => css.cx(
  css`
    color: var(--color-accent, blue);
    box-sizing: border-box;
    position: absolute;
    top: 0;
    left: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: bolder;
    z-index: 1;
    pointer-events: none;
    transition-property: color;
    line-height: 0.65;
    user-select: none;
  `,
  css.dynamic({
    'padding-bottom': LABEL_VERTICAL_PADDING_SIZES[size],
    'font-size': SECONDARY_TEXT_SIZES[size],
  }),
  css.if (border) (
    css`
      background-color: var(--color-bg, white);
    `
  ),
  css.if (style === TextControlStyle.ALTERNATE) (
    css.dynamic({
      'padding-top': `calc(${LABEL_VERTICAL_PADDING_SIZES[size]} * 0.5)`,
    }),
    css.if (border) (
      css`
        padding-left: 0.5rem;
      `,
      css.dynamic({
        'padding-right': indicator ? MIN_HEIGHTS[size] : '0.5rem',
      }),
    ),
    css.if (!border && indicator) (
      css.dynamic({
        'padding-right': MIN_HEIGHTS[size],
      }),
    ),
  ),
  css.if (style === TextControlStyle.DEFAULT) (
    css`
      padding-left: 0.5rem;
    `,
    css.dynamic({
      'padding-top': LABEL_VERTICAL_PADDING_SIZES[size],
      'padding-right': !indicator ? '0.5rem' : MIN_HEIGHTS[size],
    }),
  ),
)

export const Input = ({
  style,
  size,
  indicator,
  border,
  resizable,
  predefinedValues,
}: TextControlBaseArgs): string => css.cx(
  css`
    appearance: none;
    display: block;
    box-sizing: border-box;
    position: relative;
    border: 0;
    border-radius: inherit;
    margin: 0;
    font-family: inherit;
    min-width: 8rem;
    max-width: 100%;
    width: 100%;
    z-index: 1;
    transition-property: background-color, color;
    &:focus {
      outline: 0;
      color: var(--color-fg, black);
    }
    &:disabled {
      cursor: not-allowed;
      opacity: 0.5;
    }
    &:disabled ~ * {
      opacity: 0.5;
    }
  `,
  css.media('only screen') (
    css`
      background-color: var(--color-bg, white);
      color: var(--color-fg, black);
    `
  ),
  css.dynamic({
    'min-height': MIN_HEIGHTS[size],
    'font-size': INPUT_FONT_SIZES[size],
  }),
  css.if (resizable) (
    css`
      resize: vertical;
    `
  ),
  css.if (predefinedValues) (
    css`
      cursor: pointer;
    `
  ),
  css.if (border) (
    css`
      background-color: var(--color-bg, white);
    `
  ),
  css.if (style === TextControlStyle.ALTERNATE) (
    css`
      padding-bottom: 0;
    `,
    css.dynamic({
      'padding-top': resizable
        ? `calc(${SECONDARY_TEXT_SIZES[size]} * 2.5)`
        : `calc(${SECONDARY_TEXT_SIZES[size]} * 2)`,
      'line-height': `calc(${MULTILINE_VERTICAL_PADDING_FACTORS[size]} * 1.1)`,
    }),
    css.if (border) (
      css`
        padding-left: 0.5rem;
      `,
      css.dynamic({
        'padding-right': indicator ? MIN_HEIGHTS[size] : '0.5rem',
      }),
    ),
    css.if (!border && indicator) (
      css.dynamic({
        'padding-right': MIN_HEIGHTS[size],
      }),
    )
  ),
  css.if (style === TextControlStyle.DEFAULT) (
    css`
      padding-left: 1rem;
    `,
    css.dynamic({
      'padding-right': !indicator ? '1rem' : MIN_HEIGHTS[size],
      'line-height': `calc(${MULTILINE_VERTICAL_PADDING_FACTORS[size]} * 1.1)`,
    }),
    css.if (resizable) (
      css.dynamic({
        'padding-top': `calc(${SECONDARY_TEXT_SIZES[size]} * ${MULTILINE_VERTICAL_PADDING_FACTORS[size]})`,
        'padding-bottom': `calc(${SECONDARY_TEXT_SIZES[size]} * ${MULTILINE_VERTICAL_PADDING_FACTORS[size]})`,
      })
    ),
    css.if (!resizable) (
      css.dynamic({
        'padding-bottom': `calc(${SECONDARY_TEXT_SIZES[size]} * ${MULTILINE_VERTICAL_PADDING_FACTORS[size]} * 0.5)`,
      })
    )
  ),
)

export const HintWrapper = ({
  style,
  size,
  border,
}: TextControlBaseArgs): string => css.cx(
  css`
    box-sizing: border-box;
    position: absolute;
    left: 0;
    font-size: 0.85em;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    z-index: 1;
    pointer-events: none;
    user-select: none;
    line-height: 0;
  `,
  css.if (border) (
    css`
      background-color: var(--color-bg, white);
    `
  ),
  css.if (style === TextControlStyle.ALTERNATE) (
    css`
      line-height: 1.25;
    `,
    css.dynamic({
      top: `calc(${SECONDARY_TEXT_SIZES[size]} * ${ALTERNATE_VERTICAL_PADDING_FACTORS[size]})`,
      'font-size': SECONDARY_TEXT_SIZES[size],
    }),
    css.if (border) (
      css`
        padding-left: 0.5rem;
        &:last-child {
          padding-right: 0.5rem;
        }
      `,
      css.dynamic({
        'padding-right': MIN_HEIGHTS[size],
      })
    )
  ),
  css.if (style === TextControlStyle.DEFAULT) (
    css`
      bottom: 0;
      padding-left: 1rem;
      line-height: 1.25;
      &:last-child {
        padding-right: 1rem;
      }
    `,
    css.dynamic({
      'padding-bottom': `calc(${LABEL_VERTICAL_PADDING_SIZES[size]} * 0.9)`,
      'padding-right': MIN_HEIGHTS[size],
      'font-size': SECONDARY_TEXT_SIZES[size],
    })
  )
)

export const Hint = (): string => css.cx(
  css`
    opacity: 0.5;
  `
);

export const IndicatorWrapper = ({
  size
}: TextControlBaseArgs): string => css.cx(
  css`
    color: var(--color-accent, blue);
    box-sizing: border-box;
    position: absolute;
    bottom: 0;
    right: 0;
    display: grid;
    place-content: center;
    padding: 0 1rem;
    z-index: 2;
    pointer-events: none;
    transition-property: color;
    line-height: 1;
    user-select: none;
  `,
  css.dynamic({
    width: MIN_HEIGHTS[size],
    height: MIN_HEIGHTS[size],
  }),
);

export const Indicator = (): string => css.cx(
  css`
    width: 1.5em;
    height: 1.5em;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
  `,
);