import React from 'react';
import { bool, string, func, node, shape } from 'prop-types';
import styled from 'styled-components';
import {
  media,
  REM_UNIT_MD,
  REM_UNIT_LG,
  REM_UNIT_XLG,
  FONT_BOLD,
  STEEL_BLUE,
  CHARLESTON_GREEN,
  GRAY_X11,
  SONIC_SILVER,
  SUNSET_ORANGE,
  VERY_LIGHT_TANGELO,
} from '@vincent_za/styles';
import { PROP_ASYNC_STATUS_OPTIONAL } from '@vincent_za/utils';
import { addSvg, subtractSvg } from '@vincent_za/assets';
import scrollHOC from '../../Scroll/component';
import { SpinnerLoader } from '../../Loader';
import { ErrorFloat } from '../../Error';
import Svg from '../../Svg/component';
import SearchRF from '../Search/component';

export const CLASSNAME_SECTION_TITLE = 'section-title';
export const CLASSNAME_ACCORDION_TOGGLE = 'accordion-toggle';
export const CLASSNAME_SECTION_CONTENT = 'section-content';

const Wrap = styled.div`
  position: relative;
  display: ${props => props.isHidden ? 'none' : 'flex'};
  flex-direction: column;
  margin-right: -2px;
  padding: ${REM_UNIT_XLG} 0 0;
  min-width: 100%;
  background-color: #eee;
  box-shadow: ${props => `-4px -2px 0px -2px ${props.accentColor}, -4px 2px 0px -2px ${props.accentColor}`};

  ${props => props.isDisabled && `
    pointer-events: none;
    opacity: 0.3;
  `};
`;

const WrapScroll = scrollHOC(Wrap);

const TitleWrap = styled.div`
  display: flex;
  align-items: center;
  margin-bottom: ${props => (props.isAccordion && !props.isOpen) || props.isInitial || props.isNoContent ? 0 : REM_UNIT_MD};
  padding: 0 ${REM_UNIT_LG};
  height: 1.2rem;
  text-transform: uppercase;
  font-family: ${FONT_BOLD};
  color: ${props => props.accentColor};
`;

const Title = styled.span`
  flex-grow: 1;
`;

const ActionsWrap = styled.div`
  display: flex;
  position: relative;
  align-items: center;
`;

const ErrorFloatStyled = styled(ErrorFloat)`
  position: relative;
  margin-left: ${REM_UNIT_MD};
`;

const AccordionToggle = styled.div`
  ${props => props.isDisabled && `
    pointer-events: none;
    opacity: 0.6;
  `};
`;

const AccordionSvg = styled(Svg)`
  display: ${props => props.isVisible ? 'block' : 'none'};
  margin-left: ${REM_UNIT_LG};
  width: 1.4rem;
  height: 1.4rem;

  svg {
    fill: ${props => props.isOpen ? GRAY_X11 : SONIC_SILVER};

    &:hover {
      fill: ${GRAY_X11};
    }
  }
`;

const Content = styled.div`
  padding-bottom: ${props => props.isResponsiveAndOpen ? REM_UNIT_MD : REM_UNIT_XLG};

  ${media.sm`
    padding-bottom: ${REM_UNIT_XLG};
  `};
`;

const ContentScroll = scrollHOC(Content);

class PageSection extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isOpen: this.props.isOpenByDefault,
    };
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (nextState.isOpen !== this.state.isOpen) return true;

    if (nextProps.isHidden !== this.props.isHidden) return true;
    if (nextProps.isNoContent !== this.props.isNoContent) return true;
    if (nextProps.isOpenByDefault !== this.props.isOpenByDefault) return true;
    if (nextProps.isAccordionDisabled !== this.props.isAccordionDisabled) return true;
    if (nextProps.title !== this.props.title) return true;
    if (nextProps.fieldName !== this.props.fieldName) return true;
    if (nextProps.formName !== this.props.formName) return true;
    if (nextProps.asyncStatus !== this.props.asyncStatus) return true;
    if (nextProps.children !== this.props.children) return true;
    return false;
  }

  componentDidUpdate(prevProps) {
    if (prevProps.isOpenByDefault !== this.props.isOpenByDefault) {
      this.setState({
        isOpen: this.props.isOpenByDefault,
      });
    }
  }

  openAccordion = () => {
    this.setState({
      isOpen: true,
    });
  }

  closeAccordion = () => {
    this.setState({
      isOpen: false,
    });
  }

  render() {
    const { isOpen } = this.state;
    const {
      isTouchDevice,
      isSearch,
      isAccordion,
      isAccordionDisabled,
      isTableResponsive,
      isHidden,
      isDisabled,
      isNoContent,
      title,
      actionTemplate,
      fieldName,
      formName,
      children,
      className,
      onSearchReset,
      onChange,

      hasAsyncStatus,
      isSpinnerAlwaysVisible,
      isInfoErrorVariant,
      infoMessage,
      asyncStatus,
    } = this.props;
    const { isInitial, isSuccessful, isError } = asyncStatus;
    const determineIsInfoErrorVariant = hasAsyncStatus && asyncStatus.isSuccessful && isInfoErrorVariant;
    const accentColor = isError ? SUNSET_ORANGE : determineIsInfoErrorVariant ? VERY_LIGHT_TANGELO : STEEL_BLUE;

    return (
      <WrapScroll
        isTouchDevice={isTouchDevice}
        isHidden={isHidden}
        isDisabled={isDisabled}
        isOverflowX
        accentColor={accentColor}
        className={className}
      >
        <TitleWrap
          accentColor={accentColor}
          isAccordion={isAccordion}
          isOpen={isOpen}
          isNoContent={isNoContent}
          isError={isError}
          isInitial={isInitial}
          className={CLASSNAME_SECTION_TITLE}
        >
          <Title>
            {title}
          </Title>
          {actionTemplate && <ActionsWrap>{actionTemplate}</ActionsWrap>}
          {
            !isInitial && isSearch && isSuccessful &&
            <SearchRF
              form={formName}
              fieldName={fieldName}
              onSearchReset={onSearchReset}
              onChange={onChange}
            />
          }
          {
            isAccordion && !isNoContent &&
            <AccordionToggle isDisabled={isAccordionDisabled || isError}>
              <AccordionSvg
                isVisible={!isOpen && !isInitial}
                svg={addSvg}
                className={CLASSNAME_ACCORDION_TOGGLE}
                onClick={this.openAccordion}
              />
              <AccordionSvg
                isOpen
                isVisible={isOpen && !isInitial}
                svg={subtractSvg}
                className={CLASSNAME_ACCORDION_TOGGLE}
                onClick={this.closeAccordion}
              />
            </AccordionToggle>
          }
          {
            hasAsyncStatus &&
            <SpinnerLoader isAlwaysVisible={isSpinnerAlwaysVisible} asyncStatus={asyncStatus} size={2} isStatic />
          }
          <ErrorFloatStyled
            isInfoVariantMaybe={determineIsInfoErrorVariant}
            hasAsyncStatus={hasAsyncStatus}
            infoMessage={infoMessage}
            asyncStatus={asyncStatus}
            tooltipPosition="left"
          />
        </TitleWrap>
        <ContentScroll
          isTouchDevice={isTouchDevice}
          isOverflowX
          isResponsiveAndOpen={isTableResponsive && isOpen}
          className={CLASSNAME_SECTION_CONTENT}
        >
          {!isAccordion && children}
          {isAccordion && isOpen && children}
        </ContentScroll>
      </WrapScroll>
    );
  }
}

PageSection.propTypes = {
  isTouchDevice: bool.isRequired,
  isSearch: bool,
  isAccordion: bool,
  isOpenByDefault: bool,
  isAccordionDisabled: bool,
  isTableResponsive: bool,
  isHidden: bool,
  isDisabled: bool,
  isNoContent: bool,
  actionTemplate: node,
  title: string.isRequired,
  fieldName: string,
  formName: string,
  children: node.isRequired,
  className: string,
  onSearchReset: func,
  onChange: func,

  hasAsyncStatus: bool,
  isSpinnerAlwaysVisible: bool,
  isInfoErrorVariant: bool,
  infoMessage: string,
  asyncStatus: shape(PROP_ASYNC_STATUS_OPTIONAL),
};

PageSection.defaultProps = {
  isSearch: false,
  isAccordion: false,
  isOpenByDefault: false,
  isAccordionDisabled: false,
  isTableResponsive: false,
  isHidden: false,
  isDisabled: false,
  isNoContent: false,
  actionTemplate: undefined,
  fieldName: undefined,
  formName: undefined,
  className: undefined,
  onSearchReset() {},
  onChange() {},

  hasAsyncStatus: false,
  isSpinnerAlwaysVisible: false,
  isInfoErrorVariant: false,
  infoMessage: undefined,
  asyncStatus: {},
};

export default PageSection;
