import * as React from 'react';

import {
  Props,
  State
} from './type';
import {
  Container,
  NavBox,
  NavBoxPlace,
  NavItems,
  NavItem,
  ContentItem,
  ContentItemEditTip,
  ListMode
} from './index.style';
import linearScrollTo from '../utils/linearScrollTo';

export class Tab extends React.Component<Props, State> {
  static defaultProps = new Props();
  state = new State();

  private containerNode: HTMLElement;

  private navBoxNode: HTMLElement;
  private contentItemNodes: {
    [propsName: string]: HTMLElement
  } = {};

  handleNavItemClick(index: number) {
    if (this.props.tabType === 1) {
      this.scrollToView(index);
    } else {
      this.setState({
        selectedIndex: index
      });
    }
  }

  handleScroll = () => {
    if (this.props.tabFixed) {
      const containerRect = this.containerNode.getBoundingClientRect();
      const containerHeight = containerRect.bottom - containerRect.top;
      const navBoxReact = this.navBoxNode.getBoundingClientRect();
      const navBoxHeight = navBoxReact.bottom - navBoxReact.top;
      if (containerRect.top <= 0) {
        // to fixed
        if (containerRect.bottom <= navBoxHeight) {
          // 不超出 容器总高度
          this.navBoxNode.style.position = 'absolute';
          this.navBoxNode.style.top = containerHeight - navBoxHeight + 'px';
        } else {
          this.navBoxNode.style.position = 'fixed';
          this.navBoxNode.style.top = '0px';
        }
      } else {
        // not fixed
        this.navBoxNode.style.position = 'absolute';
        this.navBoxNode.style.top = '0px';
      }
    }

    this.changeSelectedByPosition();
  }

  changeSelectedByPosition() {
    if (this.props.tabType === 1) {
      const navBoxReact = this.navBoxNode.getBoundingClientRect();
      const navBoxHeight = navBoxReact.bottom - navBoxReact.top;

      let currentOffset = -Infinity;
      let currentIndex: null | number = null;

      Object.keys(this.contentItemNodes).forEach((itemIndex) => {
        const itemNode = this.contentItemNodes[itemIndex];
        if (itemNode) {
          const itemRect = itemNode.getBoundingClientRect();
          const offset = itemRect.top - navBoxHeight;
          if (
            offset <= 0
            && offset > currentOffset
          ) {
            currentOffset = offset;
            currentIndex = +itemIndex;
          }
        }
      })

      if (
        typeof currentIndex === 'number'
        && this.state.selectedIndex !== currentIndex
      ) {
        this.setState({
          selectedIndex: currentIndex
        })
      }
    }
  }

  changeSelectedByHash() {
    const {
      instanceKey,
      autoScrollToView
    } = this.props;
    const hash = window.location.href;
    const activeIndexReg = new RegExp(`${instanceKey}-(\\d+)`);

    const regResult = activeIndexReg.exec(hash);
    if (regResult) {
      const targetSelectedIndex = +regResult[1];
      if (this.contentItemNodes[targetSelectedIndex]) {
        this.setState({
          selectedIndex: targetSelectedIndex
        }, () => {
          if (autoScrollToView) {
            this.scrollToView(targetSelectedIndex);
          }
        })
      }
    }
  }

  scrollToView(index: number, options?: { animation: number }) {
    const node = this.contentItemNodes[index];
    let animation = 400;
    if (options && typeof options.animation === 'number') {
      animation = options.animation;
    }
    if (node) {
      const navBoxReact = this.navBoxNode.getBoundingClientRect();
      const nodeRect = node.getBoundingClientRect();
      const targetY = Math.ceil(window.pageYOffset + nodeRect.top - (navBoxReact.bottom - navBoxReact.top));
      if (animation) {
        linearScrollTo(
          targetY,
          animation
        )
      } else {
        window.scrollTo(0, targetY);
      }
    }
  }

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll);
    // 默认进行一次校准
    this.handleScroll();

    this.changeSelectedByHash();
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
  }

  public render() {
    const {
      selectedIndex
    } = this.state;
    const {
      listStyle,
      marginColor,
      marginLR,
      backgroudColor,
      instanceKey,
      isEdit,
      style,
      type,
      tabType,
      marginTop,
      tabs,
      children,
      tabColor,
      tabHeight
    } = this.props;
    // console.log('tab图高度',tabHeight,'tab图宽度',tabs[0].focusImage?.width)
    // 点击和未点击状态图片大小要一模一样，目前所有宽高取决于第一张点击状态Tab图的宽高
    return (
      <Container
        style={{ ...style, marginTop: `${marginTop}rem` }}
        ref={(container) => { this.containerNode = container; }}
        className={listStyle ? 'list' : ''}
        marginColor={marginColor}
      >
        <ListMode className={listStyle ? 'list' : ''}
          marginLR={marginLR}
          backgrondColor={backgroudColor}>
          <NavBoxPlace tabHeight={tabHeight} />
          <NavBox
            ref={(navBox) => { this.navBoxNode = navBox; }}
            tabHeight={tabHeight}
            tabColor={tabColor}
            style={{
              width: style.width
            }}
          >
            <NavItems
              className={`type-${type}`}
              marginLR={marginLR}
              tabHeight={tabHeight}
              style={{
                width: style.width
              }}
            >
              {
                tabs.map((tab, index) => (
                  <NavItem
                    tabHeight={tabHeight}
                    key={`${tab.name}-${index}`}
                    className={`type-${type} ${selectedIndex === index ? 'active' : ''}`}
                    onClick={() => this.handleNavItemClick(index)}
                  >
                    {
                      type !== 4 && <span>{tab.name}</span>
                    }
                    {
                      type === 4 && <img src={selectedIndex === index ? tabs[index].focusImage?.url : tabs[index].unfocusImage?.url}></img>
                    }
                  </NavItem>
                ))
              }
            </NavItems>
          </NavBox>
          {
            (!Array.isArray(children))
              ? children
              : children.map((child, index) => {
                const tabName = tabs[index] && tabs[index].name;
                const selected = index === selectedIndex;

                return (
                  <ContentItem
                    id={`${instanceKey}-${index}`}
                    ref={(element) => { this.contentItemNodes[index] = element; }}
                    key={index}
                    isEdit={isEdit}
                    tabType={tabType}
                    selected={selected}
                  >
                    {(isEdit || selected) && child}
                    {
                      isEdit && (
                        <ContentItemEditTip>
                          编辑Tab: {tabName || '未命名'}
                        </ContentItemEditTip>
                      )
                    }
                  </ContentItem>
                )
              })
          }

        </ListMode>
      </Container>
    )
  }
}