import { letterData, letterWidthData, letterPosOffset } from "./letterPointData";
import { asyncDelay } from "./utils";

cc.Class({
    extends: cc.Component,

    properties: {
        drawNode: cc.Node,
        letter: 'A'
    },

    ctor() {
    },

    start() {
        this.initData();
        this.initListener();
    },

    initData() {
        console.log('initData');
        this._writingIdx = 0;
        this.letterPosList = {};
        for (const key in letterData) {
            if (Object.hasOwnProperty.call(letterData, key)) {
                this.letterPosList[key] = letterData[key].map(pen => {
                    return pen.map(pos => cc.v2(pos.x, pos.y));
                });
            }
        }
    },

    initListener() {
        const BtnNext = cc.find('BtnNext', this.node);
        BtnNext.on('click', () => {
            const posList = this.letterPosList[this.letter];
            posList.push([]);
            this.updateEditMode();
        });

        const BtnBack = cc.find('BtnBack', this.node);
        BtnBack.on('click', () => {
            const posList = this.letterPosList[this.letter];
            const lastPen = posList[posList.length - 1];
            if (lastPen && lastPen.length > 0) {
                lastPen.pop();
            } else {
                if (posList.length > 0) {
                    posList.pop();
                }
            }
            this.updateEditMode();
        });

        const BtnShow = cc.find('BtnShow', this.node);
        BtnShow.on('click', () => {
            this.showLetterAnimation();
        });

        const BtnSave = cc.find('BtnSave', this.node);
        BtnSave.on('click', () => {
            const posList = this.letterPosList[this.letter];
            console.log(JSON.stringify(posList.map(list => list.map(pos => {
                return { x: pos.x, y: pos.y };
            }))));
        });

        this.drawNode.off('touchstart', this.onEditModeDrawNodeTouchStart.bind(this));
        this.drawNode.off('touchmove', this.onEditModeDrawNodeTouchMove.bind(this));
        this.drawNode.on('touchstart', this.onEditModeDrawNodeTouchStart.bind(this));
        this.drawNode.on('touchmove', this.onEditModeDrawNodeTouchMove.bind(this));
        this.updateEditMode();
    },

    setDrawNode(drawNode) {
        this.drawNode = drawNode;
        this.drawNode.off('touchstart', this.onEditModeDrawNodeTouchStart.bind(this));
        this.drawNode.off('touchmove', this.onEditModeDrawNodeTouchMove.bind(this));
        this.drawNode.on('touchstart', this.onEditModeDrawNodeTouchStart.bind(this));
        this.drawNode.on('touchmove', this.onEditModeDrawNodeTouchMove.bind(this));
        this.updateEditMode();
    },

    _targetPos: null,
    onEditModeDrawNodeTouchStart(event) {
        const touchLocation = event.getLocation();
        const pos = this.drawNode.convertToNodeSpaceAR(touchLocation);
        const posList = this.letterPosList[this.letter];

        const targetPos = posList.flat().find(penPos => this.getDistance(penPos, pos) < 5);
        if (targetPos) {
            targetPos.x = pos.x;
            targetPos.y = pos.y;
            this._targetPos = targetPos;
        } else {
            if (posList.length == 0) {
                posList.push([]);
            }
            posList[posList.length - 1].push(pos);
            this._targetPos = pos;
        }
        this.updateEditMode();
    },

    onEditModeDrawNodeTouchMove(event) {
        const touchLocation = event.getLocation();
        const pos = this.drawNode.convertToNodeSpaceAR(touchLocation);
        this._targetPos.x = pos.x;
        this._targetPos.y = pos.y;
        this.updateEditMode();
    },

    _writingIdx: 0,
    async showLetterAnimation() {
        this._writingIdx++;
        const writingIdx = this._writingIdx;

        const graphsmall = this.drawNode.getComponent(cc.Graphics);
        graphsmall.clear();

        const posList = this.letterPosList[this.letter];
        const lineList = this.getLineList(posList);

        for (const pen of lineList) {
            for (const line of pen) {
                if (writingIdx == this._writingIdx) {
                    this.drawALine(this.drawNode, line.startPos, line.endPos, cc.color(181, 39, 48));
                }
                await asyncDelay(0.02);
            }
            await asyncDelay(0.1);
        }
    },

    updateEditMode() {
        const graph = this.drawNode.getComponent(cc.Graphics)
        graph.clear();
        const posList = this.letterPosList[this.letter];

        const lineList = this.getLineList(posList);
        for (const pen of lineList) {
            for (const line of pen) {
                this.drawALine(this.drawNode, line.startPos, line.endPos, cc.color(0, 0, 255));
            }
        }
        posList.forEach((pen, i) => {
            const newPen = this.interpolatePos(pen, 10);
            for (const pos of newPen) {
                let color = cc.color(50, 50, 50);
                if (i == posList.length - 1) {
                    color = cc.color(255, 0, 0);
                }
                const idx = pen.findIndex(penPos => penPos.x == pos.x && penPos.y == pos.y);
                if (idx == -1) {
                    this.drawSmallDot(this.drawNode, pos, color);
                } else {
                    this.drawBigCircle(this.drawNode, pos, color);
                }
            }
        });
    },

    getLineList(posList) {
        const lineList = [];
        for (const pen of posList) {
            const newPen = this.interpolatePos(pen, 10);
            const newLine = [];
            newPen.forEach((pos, idx) => {
                if (idx < newPen.length - 1) {
                    newLine.push({
                        startPos: pos,
                        endPos: newPen[idx + 1]
                    });
                }
            });
            if (pen.length == 1) {
                newLine.push({
                    startPos: pen[0],
                    endPos: cc.v2(pen[0].x, pen[0].y + 0.001)
                });
            }
            lineList.push(newLine);
        }
        return lineList;
    },

    interpolatePos(posList, maxLength) {
        let newposList = [];
        if (posList.length <= 1) {
            return posList;
        }
        for (let i = 0; i < posList.length - 1; i++) {
            const pos = posList[i];
            const nextPos = posList[i + 1];
            const distance = this.getDistance(pos, nextPos);

            newposList.push(pos);
            if (distance > maxLength) {
                const middlePoint = this.getMiddlePoint(pos, nextPos);
                newposList.push(middlePoint);
            }
        }
        newposList.push(posList[posList.length - 1]);
        if (newposList.length > posList.length) {
            newposList = this.interpolatePos(newposList, maxLength);
        }
        return newposList;
    },

    getMiddlePoint(pos1, pos2) {
        return cc.v2((pos1.x + pos2.x) / 2, (pos1.y + pos2.y) / 2);
    },

    getDistance(pos1, pos2) {
        return pos1.sub(pos2).mag();
    },

    drawALine(drawNode, fromPos, toPos, color) {
        const graph = drawNode.getComponent(cc.Graphics);
        if (color) {
            graph.strokeColor = color;
        }
        if (letterWidthData[this.letter]) {
            graph.lineWidth = letterWidthData[this.letter];
        } else {
            graph.lineWidth = letterWidthData.defaultWidth;
        }
        graph.moveTo(fromPos.x, fromPos.y);
        graph.lineTo(toPos.x, toPos.y);
        graph.stroke();
    },

    drawBigCircle(drawNode, centerPos, color) {
        const graph = drawNode.getComponent(cc.Graphics);
        graph.lineWidth = 5;
        graph.strokeColor = color;
        graph.arc(centerPos.x, centerPos.y, 6, 0, Math.PI * 2, true);
        graph.stroke();
        graph.fillColor = cc.color(255, 255, 255);
        graph.arc(centerPos.x, centerPos.y, 4, 0, Math.PI * 2, true);
        graph.fill();
    },

    drawSmallDot(drawNode, centerPos, color) {
        const graph = drawNode.getComponent(cc.Graphics);
        graph.fillColor = color;
        graph.arc(centerPos.x, centerPos.y, 3, 0, Math.PI * 2, true);
        graph.fill();
    },
});
