import { _decorator, Component, EventTouch, instantiate, Mask, math, Node, Prefab, Size, UITransform } from "cc";

const { ccclass, property, requireComponent } = _decorator;

@ccclass("VList")
@requireComponent([UITransform, Mask])
export class VList extends Component {

    @property(Prefab)
    itemPrefab: Prefab = null;

    @property
    gapX: number = 0;

    @property
    autoScroll: boolean = true;

    @property
    speed: number = 100;

    _init: boolean = false;
    _auto: boolean = true;
    _data: any = [];
    callback: (node: Node, index: number) => void = () => {};

    uiTransform: UITransform = null;

    itemSize: Size;
    itemArr: { node: Node, i: number }[] = [];

    onLoad() {
        this.uiTransform = this.getComponent(UITransform);

        this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    init(data: any[], callback: (node: Node, index: number) => void) {
        this._data = data;
        this.callback = callback;
        const node = instantiate(this.itemPrefab);
        this.node.addChild(node);
        this.itemSize = node.getComponent(UITransform).contentSize.clone();
        this.itemArr.push({ node, i: 0 });
        this.updateItem(node, 0);

        const num = ~~(this.uiTransform.width / (this.itemSize.width + this.gapX)) + 2;
        for (let i = 1; i <= num; i++) {
            const node = instantiate(this.itemPrefab);
            this.node.addChild(node);
            this.itemArr.push({ node, i });
            this.updateItem(node, i);
        }

        this.itemArr.forEach(({ node }, i) => {
            node.setPosition(i * (this.itemSize.width + this.gapX) - this.uiTransform.width * this.uiTransform.anchorX, 0);
        });

        this._init = true;
    }

    onTouchStart() {
        this._auto = false;
    }

    onTouchMove(e: EventTouch) {
        this.updateX(e.getDeltaX());
    }

    onTouchEnd() {
        this._auto = true;
    }

    update(deltaTime: number) {
        const { _auto, autoScroll, speed } = this;

        if (autoScroll && _auto) {
            this.updateX(-speed * deltaTime);
        }
    }

    updateX(deltaX: number) {
        if (!this._init) return;

        deltaX = math.clamp(deltaX, -50, 50);

        const { gapX, itemArr, itemSize, uiTransform } = this;

        const index = ~~(itemArr.length / 2);

        const newX = itemArr[index].node.position.x + deltaX;
        itemArr[index].node.setPosition(newX, 0);

        const iSize = gapX + itemSize.width;

        for (let i = index - 1; i >= 0; i--) {
            itemArr[i].node.setPosition(itemArr[i + 1].node.position.x - iSize, 0);
        }

        for (let i = index + 1; i < itemArr.length; i++) {
            itemArr[i].node.setPosition(itemArr[i - 1].node.position.x + iSize, 0);
        }
        if (deltaX < 0) {
            if (itemArr[0].node.position.x <= -(uiTransform.width * uiTransform.anchorX) - itemSize.width) {
                const newI = itemArr[itemArr.length - 1].i + 1;
                itemArr[0].i = newI;
                this.updateItem(itemArr[0].node, newI);
                itemArr.push(itemArr.shift());
            }
        } else {
            if (itemArr[itemArr.length - 1].node.position.x >= (uiTransform.width * (1 - uiTransform.anchorX)) + itemSize.width) {
                const newI = itemArr[0].i - 1;
                itemArr[itemArr.length - 1].i = newI;
                this.updateItem(itemArr[itemArr.length - 1].node, newI);
                itemArr.unshift(itemArr.pop());
            }
        }

    }

    updateItem(node: Node, index: number) {
        const dLen = this._data.length;
        const dataIndex = (dLen + index % dLen) % dLen;
        this.callback(node, this._data[dataIndex]);
    }
}


