import * as React from 'react'
import { Props, State } from './type'
import * as Styled from './style'
import getOffsetTop from '../utils/getOffsetTop'
import { easeInOutCubic } from '../utils/animate'
import getScroll from '../utils/getScroll'
import raf from 'raf'
import BScroll from 'better-scroll'


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

  public sharpMatcherRegx = /#([^#]+)$/;

  public bounds:number = 5;

  public animating:boolean = false;

  public anchorContainerParent:any = null;

  public scrollWrap:any = null;

  public anchorContainerDom:any = null;

  public AnchorContainerScroll:any;

  /**
   * 获取当前高亮锚点
   */
  public getCurrentAnchor() {
    let anchorSections = [];
    this.props.anchorData.forEach((anchor) => {
      let { anchorId } = anchor;
      if(!anchorId){
        return;
      }
      let target = document.getElementById(anchorId);
      if (target) {
        let top = getOffsetTop(target, this.anchorContainerDom);
        if (top < this.bounds) {
          anchorSections.push({
            anchor: anchor,
            top: top
          });
        }
      }
    });

    if (anchorSections.length) {
      var maxSection = anchorSections.reduce(function (prev, curr) {
        return curr.top > prev.top ? curr : prev;
      });
      return maxSection.anchor.anchorId;
    }
    return '';
  }

  public scrollTo(anchor, callback) {
    let scrollTop = getScroll(window, true);
    let targetElement = document.getElementById(anchor);
    if (!targetElement) {
      return;
    }

    let targetScrollTop = getOffsetTop(targetElement, document.body);
    let startTime = Date.now();
    let frameFunc = () => {
      let timestamp = Date.now();
      let time = timestamp - startTime;
      let nextScrollTop = easeInOutCubic(time, scrollTop, targetScrollTop, 450);
      window.scrollTo(window.pageXOffset, nextScrollTop);
      if (time < 450) {
        raf(frameFunc);
      } else {
        callback();
      }
    };
    raf(frameFunc);
  }

  public handleScrollTo(anchor) {
    this.animating = true;
    this.setState({
      activeAnchor: anchor
    });

    this.scrollTo(anchor, () => {
      this.animating = false;
      let top = this.anchorContainerDom.getBoundingClientRect().top
      if(getOffsetTop(this.anchorContainerDom, this.anchorContainerParent) < 0){
        this.anchorContainerDom.style.position = 'absolute';
      }else if(top <= 0) {
        this.anchorContainerDom.style.position = 'fixed';
      }
    });

    this.adjust(anchor)
  };

  public handleScroll() {
    if (this.animating || !this.props.anchorData) {
      return;
    }

    let activeAnchor = this.state.activeAnchor;

    let currentActiveAnchor = this.getCurrentAnchor();

    if (activeAnchor !== currentActiveAnchor) {
      this.setState({
        activeAnchor: currentActiveAnchor
      });
    }

    let top = this.anchorContainerDom.getBoundingClientRect().top
    if(getOffsetTop(this.anchorContainerDom, this.anchorContainerParent) < 0){
      this.anchorContainerDom.style.position = 'absolute';
    }else if(top <= 0) {
      this.anchorContainerDom.style.position = 'fixed';
    }

    this.adjust(currentActiveAnchor)

  }

  public adjust(anchorId) {
    if(this.props.type == 1){
      return;
    }
    if(!anchorId && this.AnchorContainerScroll){
      this.AnchorContainerScroll.scrollTo(0, 0, 0)
      return
    }
    const viewportWidth = this.anchorContainerParent.clientWidth
    const tabListWidth = this.anchorContainerDom.clientWidth
    const minTranslate = Math.min(0, viewportWidth - tabListWidth)
    const middleTranslate = viewportWidth / 2
    const items = this.anchorContainerDom.children
    let width = 0
    this.props.anchorData.every((item, index) => {
      if (item.anchorId === anchorId) {
        return false
      }
      width += items[index].clientWidth
      return true
    })
    let translate = middleTranslate - width
    translate = Math.max(minTranslate, Math.min(0, translate))
    this.AnchorContainerScroll && this.AnchorContainerScroll.scrollTo(translate, 0, 300)
  }

  public componentDidMount() {
    if(this.props.type == 1){
      this.anchorContainerDom.style.width = `${this.anchorContainerDom.offsetWidth}px`;
    }
    
    if(!this.props.isEdit && this.props.type == 2){
      //横向滚动样式
      const wrapper = this.scrollWrap
      this.AnchorContainerScroll = new BScroll(wrapper, {
        scrollX: true,
        click: true,
        scrollY: false
      })
    }

    window.addEventListener('scroll', () => this.handleScroll());
    this.handleScroll();
  }

  public render() {
    let { style, backgroundColor, color, activeColor, type, marginTop} = this.props
    const isDefaultTheme = backgroundColor.toLowerCase() === '#fff' && color === '#333' && activeColor === '#d33a31';
    return (
      <Styled.AnchorContainer ref={(ref) => this.anchorContainerParent = ref} style={style}>
        <div className={marginTop && 'f-before'}>
          <div ref={(ref) => this.scrollWrap = ref} className="anchor-wrap j-scroll-wrapper" style={{marginTop: `${marginTop}rem`, overflow: 'hidden'}}>
            <Styled.AnchorUl ref={(ref) => this.anchorContainerDom = ref} className={`anchor-ul type-${type}`} theme={{backgroundColor, isDefaultTheme}}>
              {this.props.anchorData && this.props.anchorData.map((data, index) => {
                let { anchorName, anchorId, focusImage, unfocusImage } = data;
                if (focusImage) {
                  focusImage = focusImage.url;
                }
                if (unfocusImage) {
                  unfocusImage = unfocusImage.url;
                }
                return (
                  <Styled.AnchorLi key={anchorId + index} className={anchorId === this.state.activeAnchor ? `active anchor-li type-${type}` : `anchor-li type-${type}`} theme={{ color, activeColor, isDefaultTheme,unfocusImage,focusImage}}>
                    <a onClick={() => this.handleScrollTo(anchorId)}>
                      <span className="indicator-name">{anchorName}</span>
                      <span className="line"></span>
                    </a>
                  </Styled.AnchorLi>
                )
              })}
            </Styled.AnchorUl>
          </div>
        </div>
      </Styled.AnchorContainer>
    )
  }
}
