// @flow
import React, { type Node } from 'react';
import styled, { css, useTheme } from 'styled-components';
import { Box } from '../../../primitives';
import { getCardBorderRadius } from './forms.css-rules';
import { getPaletteColor } from '../../../mixins/branding';
import { getFontSize } from '../../../mixins/typography';
import type { FormFieldError } from './forms.proptypes';
import { Text } from '../../typography/text';
import { type ThemeProps } from '../../../types';

export const FLOAT_LABEL_ANIM_FUNC = `0.3s cubic-bezier(0.65, 0, 0.35, 1)`;

const getFloatLabelTranslateAmount = ({ theme, labelStyle }) =>
  labelStyle === 'floating' ? theme.spacing.s1 : 0;

const getFormBoxBackgroundColor = (props) =>
  getPaletteColor(props.disabled || props.readOnly ? 'background' : 'white')(
    props,
  );

const getFloatTransform = ({ theme, fontSize }) => {
  const factor =
    parseInt(theme.typescale.f0, 10) /
    parseInt(getFontSize({ theme, fontSize }), 10);
  return `scale3D(${factor}, ${factor}, 1)`;
};

export const FormRow = styled(Box)`
  && {
    min-height: 44px;

    :last-child {
      border-bottom: 0;
    }

    &:not(:last-child) {
      border-bottom: 1px solid ${getPaletteColor('greyscale-light')};
    }
  }

  &:first-child {
    border-top-left-radius: ${getCardBorderRadius};
    border-top-right-radius: ${getCardBorderRadius};
  }

  &:last-child {
    border-bottom-left-radius: ${getCardBorderRadius};
    border-bottom-right-radius: ${getCardBorderRadius};
  }
`;

/* Floating label implementation:
 * You must add floatingLabelInputStyles to the input who's focus we are
 * watching.  Then, put both the `<FloatingLabel>` and the `<input>` as siblings
 * inside a `<FormBox>` for the magic to happen.
 */
type FloatingLabelProps = {|
  isEmbeddable?: boolean,
  hasLeftIcon?: boolean,
|};
export const FloatingLabel = styled.label`
  color: ${({
    isEmbeddable,
    theme,
  }: {|
    ...FloatingLabelProps,
    ...ThemeProps,
  |}) =>
    isEmbeddable ? undefined : getPaletteColor('greyscale-dark')({ theme })};
  display: block;
  left: ${({
    hasLeftIcon,
    theme,
    isEmbeddable,
  }: {|
    ...FloatingLabelProps,
    ...ThemeProps,
  |}) => (hasLeftIcon || isEmbeddable ? '0' : theme.spacing.s2)};
  pointer-events: none;
  position: absolute;
  transition: transform ${FLOAT_LABEL_ANIM_FUNC}, top ${FLOAT_LABEL_ANIM_FUNC};
  transform-origin: top left;
  font-size: ${getFontSize};
  line-height: 1;
  text-align: left;
  font-weight: ${({ isEmbeddable }: FloatingLabelProps) =>
    isEmbeddable ? 'normal' : 'bold'};
  top: ${({ theme }: ThemeProps) => theme.spacing.s2};
`;

/**
 * Include this CSS snippet in the input associated with a floating label.
 * This is what un-hides the placeholder and pushes the input down inside
 * the form box to make room for the floated label.
 */
export const floatingLabelInputStyles = css`
  transition: transform ${FLOAT_LABEL_ANIM_FUNC},
    opacity ${FLOAT_LABEL_ANIM_FUNC};
  opacity: ${({ labelStyle }) => (labelStyle === 'floating' ? '0' : '1')};

  &:focus,
  &[data-has-value='true'] {
    opacity: 1;
    transform: translate3d(0, ${getFloatLabelTranslateAmount}, 0);
  }
`;

export const FormBox = styled(Box)`
  font-size: ${getFontSize};
  border: 1px solid ${getPaletteColor('greyscale-light')};
  border-radius: ${getCardBorderRadius};
  cursor: text;
  position: relative;
  transition: border-color ${FLOAT_LABEL_ANIM_FUNC};
  background-color: ${getFormBoxBackgroundColor};

  &:focus-within {
    border: 1px solid ${getPaletteColor('greyscale-black')};
  }

  &:focus-within ${FloatingLabel}, ${FloatingLabel}[data-has-value='true'] {
    color: ${getPaletteColor('greyscale-dark')};
    top: ${getFloatLabelTranslateAmount};
    transform: ${getFloatTransform};
  }

  &:hover:not(:focus-within):not([disabled]) {
    border: 1px solid ${getPaletteColor('greyscale-medium')};
  }
`;

type ErrorMessageProps = {| message: FormFieldError |};
export const ErrorMessage = ({ message }: ErrorMessageProps) => (
  <Text spacing={['mt1', 'mb0']} fontSize="f1" colorName="error-fg">
    {Array.isArray(message) ? message.join(', ') : String(message)}
  </Text>
);

type SuccessMessageProps = {| message: Node |};
export const SuccessMessage = ({ message }: SuccessMessageProps) => (
  <Box stacked="row" align="center" spacing="mt1">
    <Text spacing={['mb0', 'mr1']} fontSize="f1" colorName="success-fg">
      {message}
    </Text>
    <MiniCheckmark />
  </Box>
);

type FieldInfoProps = {| message?: Node |};
export const Description = ({ message }: FieldInfoProps) => (
  <Text spacing="mt1" fontSize="f1" colorName="greyscale-dark">
    {message}
  </Text>
);

const MiniCheckmark = () => {
  const theme = useTheme();
  return (
    <svg width="10" height="8" viewBox="0 0 10 8" fill="none">
      <path
        d="M1 4.23077L3.66667 7L9 1"
        stroke={theme.colorPalette['success-fg']}
        strokeWidth="2"
        strokeMiterlimit="10"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
};
