import { Component, createRef } from "react";
import PropTypes from "prop-types";
import { gsap, ScrollTrigger } from "gsap/all";
import styled from "@emotion/styled";
import { css } from "@emotion/react";

export default class Viewer extends Component {
  constructor() {
    super();
    console.log("hello constructor");
    //ref
    this.containerRef = createRef(null);
    this.viewerRef = createRef(null);
    this.canvasContainerRef = createRef(null);
    this.loadingWrap = createRef(null);
    this.viewerOffsetRef = createRef(null);
    this.canvasRef = createRef();

    this.sequence = [];
    this.loadedRenderPool = [];
    this.enterTimeline = false;
    this.exitTimeline = false;
    this.loadComplete = false;

    this.loadedCount = 0;
    this.progress = 0;
    this.lastFrame = -1;
    this.floatFrame = 0;
    this.loadedRenderTimeout = null;
    this.poolAnimateDelay = 40;

    this.context = null;
    this.width = 1552;
    this.height = 873;
    this.justScrolled = false;
    this.isBelow = true;
    this.isAbove = false;
  }
  static propTypes = {
    name: PropTypes.string,
    height: PropTypes.string,
    path: PropTypes.string,
    frameCount: PropTypes.number,
    enterTween: PropTypes.func,
    exitTween: PropTypes.func,
    canvasSize: PropTypes.array,
    pause: PropTypes.object,
    children: PropTypes.object,
  };

  state = {};

  componentWillUnmount() {
    this.timeline && this.timeline.kill(true);
  }

  componentDidMount() {
    this.loadAssets();
    this.canvasRef.current && this.initializeCanvas();
    if (!this.timeline) {
      this.initializeTimeline();
      this.setTimeline();
    }
    if (!this.enterTimeline && this.props.enterTween) {
      this.initializeEnterTween();
    }
    ScrollTrigger.refresh();
  }

  loadImage(index) {
    const img = new Image();
    // console.log("index", this.getSourcePath(index));
    img.retried = 0;
    img.src = this.getSourcePath(index);
    img.ogSrc = img.src;

    if (this.props.pause && index + "" in this.props.pause) {
      for (var r = this.props.pause[index]; r--; ) {
        this.sequence.push(img);
      }
    }
    this.sequence.push(img);

    img.onload = () => {
      index === 1 && this.renderImageToCanvas(0);
      if (this.frame > index && this.timeline.scrollTrigger.isActive) {
        this.poolNewFrames(index - 1);
      }
      this.loadedCount += 1;
      if (this.loadedCount === parseFloat(this.props.frameCount) - 1) {
        this.loadingComplete();
      }
    };
  }

  getSourcePath(index) {
    const defaultPrefix = import.meta.env.VITE_APP_SOURCE;
    return `${defaultPrefix}${this.props.path}/${"".concat(
      index.toString().padStart(4, "0")
    )}.webp`;
  }
  loadAssets() {
    this.loadImage(1);
    setTimeout(() => {
      for (var t = 2; t <= this.props.frameCount; t += 1) {
        this.loadImage(t);
      }
    }, 60);
  }
  loadingComplete() {
    console.log(this.props.path, "loading complete");
    this.loadComplete = true;
    this.isAbove && this.renderImageToCanvas(this.loadedCount - 1);
  }

  initializeCanvas() {
    this.context = this.canvasRef.current.getContext("2d", {
      alpha: false,
      desynchronized: true,
      powerPreference: "high-performance",
    });
    this.context.imageSmoothingEnabled = true;
    this.context.imageSmoothingQuality = "high";
  }
  initializeTimeline() {
    const openLoading = () => {
      gsap.to(this.loadingWrap.current, {
        autoAlpha: 1,
      });
    };
    const closeLoading = () => {
      gsap.to(this.loadingWrap.current, {
        autoAlpha: 0,
      });
    };
    closeLoading();
    this.timeline = gsap.timeline({
      scrollTrigger: {
        trigger: this.containerRef.current,
        pin: this.viewerRef.current,
        scrub: 0.66,
        start: "top top",
        end: "bottom bottom",
        ease: "none",
        markers: true,
        onUpdate: function (n) {
          //处理processloading
        },
        onScrubComplete: () => {
          this.justScrolled = true;
        },
        onEnter: () => {
          closeLoading();
          this.isAbove = false;
          console.log("onEnter");
        },
        onEnterBack: () => {
          openLoading();
          console.log("onEnterBack");
          this.isBelow = false;
        },
        onLeave: () => {
          console.log("onLeave");
          this.isAbove = true;
          openLoading();
        },
        onLeaveBack: () => {
          console.log("onLeaveBack");
          openLoading();
          this.isBelow = true;
        },
      },
    });
  }
  setTimeline() {
    console.log("this.fullFrameCount", this.fullFrameCount);
    this.timeline.to(this, {
      floatFrame: this.fullFrameCount - 1,
      ease: "none",
      onUpdate: () => {
        this.frame = Math.floor(this.floatFrame);
        if (this.lastFrame === this.frame || this.loadedRenderPool.length > 0) {
          this.renderImageToCanvas(this.frame);
        }
      },
    });
  }

  initializeEnterTween() {
    console.log("initializeEnterTween");
  }

  poolNewFrames(index) {
    console.log("poolNewFrames", index);
    this.loadedRenderPool.unshift(index);
    this.loadedRenderPool.sort(function (e, t) {
      return t - e;
    });
    this.animatePool();
  }
  animatePool() {
    if (!this.loadedRenderTimeout && this.loadedRenderPool.length) {
      this.loadedRenderTimeout = setTimeout(() => {
        this.loadedRenderTimeout = true;
        var poolFrame = this.loadedRenderPool[this.loadedRenderPool.length - 1];
        if (poolFrame <= this.frame) {
          var remainFrame = this.loadedRenderPool.pop();
          this.renderImageToCanvas(remainFrame);
          this.animatePool();
        }
        if (this.frame < poolFrame) {
          this.loadedRenderPool = [];
        }
      }, this.poolAnimateDelay);
    }
  }
  renderImageToCanvas(index) {
    if (this.sequence[index]) {
      if (this.context.drawImage) {
        console.log("renderImageToCanvas", index);
        this.context.drawImage(this.sequence[index], 0, 0);
        this.lastFrame = index;
      } else {
        this.initializeCanvas();
      }
    }
  }

  render() {
    // process props
    this.fullFrameCount = this.props.frameCount;
    if (this.props.pause) {
      Object.keys(this.props.pause).forEach((index) => {
        this.fullFrameCount += this.props.pause[index];
      });
    }
    const Wrapper = styled.div({
      position: "relative",
      margin: "auto",
      textAlign: "center",
      pointerEvents: "none",
      maxWidth: "100vw",
    });
    return (
      <>
        <Wrapper
          ref={this.containerRef}
          style={{ height: this.props.height || "500vh" }}
        >
          <div>{this.props.name}</div>
          <div className="loading-wrap" ref={this.loadingWrap}></div>

          <div ref={this.viewerRef}>
            <div style={{ overflow: "hidden" }}>
              <canvas
                css={css`
                  width: auto;
                  margin-left: 50%;
                  transform: translateX(-50%);
                  height: calc(var(--vh, 1vh) * 100);
                `}
                ref={this.canvasRef}
                width={this.width}
                height={this.height}
              ></canvas>
            </div>
          </div>

          <>{this.props.children}</>
        </Wrapper>
      </>
    );
  }
}
