// Learn TypeScript:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html

import Worm from "./Worm";
import { TYPEMAP } from './NodeType';
import MapManager from "./MapManager";

const { ccclass, property } = cc._decorator;

@ccclass
export default class Snake extends cc.Component {
    @property(cc.Prefab)
    header: cc.Prefab = null;

    @property(cc.Prefab)
    body: cc.Prefab = null;

    @property(cc.Prefab)
    tail: cc.Prefab = null;

    @property(cc.SpriteFrame)
    spHeader: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    spBodyBold: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    spBodyPale: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    spTurnBold: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    spTurnPale: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    spTailBold: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    spTailPale: cc.SpriteFrame = null;

    bodies: { x: number, y: number, type: number, obj: cc.Node }[] = [];
    offset: number = 0;
    isMap18: boolean = true;
    sizeBody: number = 60;
    width: number = 18;
    height: number = 10;

    private headerPos: cc.Vec3 = null;

    initializeSnakeView(worms: Worm[], offset: number, isMap18: boolean) {
        if (isMap18) {
            this.node.position.x = -535;
            this.width = 18;
            this.height = 10;
        } else {
            this.node.position.x = -530;
            this.width = 22;
            this.height = 12;
        }
        this.node.removeAllChildren();
        for (let index = 0; index < worms.length; index++) {
            if (worms[index].stt == 0) {
                let header: cc.Node = cc.instantiate(this.header);
                header.parent = this.node;
                header.getComponent(cc.Sprite).spriteFrame = this.spHeader;
                header.zIndex = 100;
                header.position = cc.v3(offset * worms[index].x, offset * worms[index].y);
                this.headerPos = header.position;
                if (isMap18) {
                    header.width = 60;
                    header.height = 60;
                } else {
                    header.width = 50;
                    header.height = 50;
                }
                this.rotationHead(header, worms[index], worms[index + 1])
                this.bodies.push({ x: worms[index].x, y: worms[index].y, type: TYPEMAP.HEAD, obj: header });
            } else if (worms[index].stt > 0 && worms[index].stt < worms[worms.length - 1].stt && worms.length > 2) {
                let body: cc.Node = cc.instantiate(this.body);
                body.parent = this.node;
                this.rotationBody(body, worms[index - 1], worms[index + 1], worms[index]);
                if (isMap18) {
                    body.scale = 0.5;
                    body.width = 120;
                    body.height = 120;
                } else {
                    body.scale = 0.5;
                    body.width = 100;
                    body.height = 100;
                }
                body.position = cc.v3(offset * worms[index].x, offset * worms[index].y);
                this.bodies.push({ x: worms[index].x, y: worms[index].y, type: TYPEMAP.HEAD, obj: body });
            } else if (worms[index].stt == worms[worms.length - 1].stt) {
                let tail: cc.Node = cc.instantiate(this.tail);
                tail.parent = this.node;
                tail.getComponent(cc.Sprite).spriteFrame = worms[index].stt % 2 ? this.spTailBold : this.spTailPale;
                if (isMap18) {
                    tail.scale = 0.5;
                    tail.width = 120;
                    tail.height = 120;
                } else {
                    tail.scale = 0.5;
                    tail.width = 100;
                    tail.height = 100;
                }
                tail.position = cc.v3(offset * worms[index].x, offset * worms[index].y);
                if (worms[index - 1].x == worms[index].x) {
                    tail.rotation = 90;
                } else if (worms[index].y == worms[index].y) {
                    tail.rotation = 0;
                }
                this.bodies.push({ x: worms[index].x, y: worms[index].y, type: TYPEMAP.HEAD, obj: tail });
            }
        }
    }

    rotationHead(node: cc.Node, posHeader, posBody) {
        if (posHeader.y == posBody.y && posHeader.x != posBody.x) {
            if (posHeader.x - posBody.x > 0) {
                node.angle = 0
                node.scale = 1;
            } else {
                node.angle = 0
                node.scale = -1;
            }
        } else if (posHeader.x == posBody.x && posHeader.y != posBody.y) {
            if (posHeader.y - posBody.y > 0) {
                node.angle = 90
                node.scale = 1;
            } else {
                node.angle = -90
                node.scale = 1;
            }
        }
    }

    rotationBody(nodeCenter: cc.Node, posBefore, posAfter, posCenter) {
        if (!posCenter || !posBefore || !posAfter) {
            return;
        }
        if (posBefore.x != posAfter.x && posBefore.y != posAfter.y) {
            nodeCenter.getComponent(cc.Sprite).spriteFrame = posCenter.stt % 2 ? this.spTurnBold : this.spTurnPale;
            if (posBefore.y == posCenter.y) {
                if (posBefore.x > posCenter.x) {
                    if (posAfter.y > posCenter.y) {
                        nodeCenter.angle = -90;
                    } else {
                        nodeCenter.angle = 180;
                    }
                } else {
                    if (posAfter.y > posCenter.y) {
                        nodeCenter.angle = 0;
                    } else {
                        nodeCenter.angle = 90;
                    }
                }

            } else if (posBefore.x == posCenter.x) {
                if (posBefore.y > posCenter.y) {
                    if (posAfter.x > posCenter.x) {
                        nodeCenter.angle = -90;
                    } else {
                        nodeCenter.angle = 0;
                    }
                } else {
                    if (posAfter.x > posCenter.x) {
                        nodeCenter.angle = 180;
                    } else {
                        nodeCenter.angle = 90;
                    }
                }
            }
        } else if (posBefore.x == posAfter.x && posCenter.x == posBefore.x && posCenter.x == posAfter.x) {
            nodeCenter.getComponent(cc.Sprite).spriteFrame = posCenter.stt % 2 ? this.spBodyBold : this.spBodyPale;
            nodeCenter.angle = 90;
        } else if (posBefore.y == posAfter.y && posCenter.y == posBefore.y && posCenter.y == posAfter.y) {
            nodeCenter.angle = 0;
        }
    }

    moveUp() {
        // this.isMoveValid(1, cc.v2(1, 0));
    }

    moveDown() {

    }

    moveLeft() {

    }

    moveRight() {

    }

    handlePlayerInput(displcement: cc.Vec2) {

    }

    async moveSnakeAndPushStone(displcement: cc.Vec2) {
        let posHeadMap = { x: this.headerPos.x / 60, y: this.headerPos.y / 60 };
        let newPos = { x: posHeadMap.x + displcement.x, y: posHeadMap.y + displcement.y };
        if (!this.isMoveValid(newPos)) {
            //ToDo
            return;
        }

        if (this.isNeedToPushStone(newPos)) {
            let originaStonePos = newPos;
			let newStonePos = { x: posHeadMap.x + (displcement.x * 2), y: posHeadMap.y + (displcement.y * 2) };
            let indexStone = MapManager.Instance.mapLevel.findStone(originaStonePos)
            MapManager.Instance.mapLevel.updateAndMoveStonePos(indexStone, newStonePos);


        }
    }

    checkAndHandleFallings() {

    }

    isMoveValid(newPos) {
        if (newPos.x > this.width || newPos.x < 0 || newPos.y > this.height || this.height < 0){
            return true;
        }
        if (this.isSpaceEmptyFor(newPos)) {
            return true;
        }
        if (this.isNeedToPushStone(newPos)) {
            return true;
        }
    }

    isSpaceEmptyFor(pos) {
        return this.getMovementMapFor()[pos.y][pos.x] == TYPEMAP.EMPTY ? true : false;
    }

    isNeedToPushStone(pos)
	{
		return this.getMovementMapFor()[pos.y][pos.x] == TYPEMAP.STONE ? true : false;
	}

    getMovementMapFor() {
        let array: number[][] = this.clone2DArray(MapManager.Instance.mapLevel.mapWall);
        let arrayStone = MapManager.Instance.mapLevel.listStone;
        let arrayApple = MapManager.Instance.mapLevel.listApple;
        for (let i = 0; i < this.bodies.length; i++) {
            if (this.bodies[i].type == TYPEMAP.HEAD) {
                array[this.bodies[i].y][this.bodies[i].x] = TYPEMAP.HEAD;
            } else {
                array[this.bodies[i].y][this.bodies[i].x] = TYPEMAP.BODY;
            }
        }
        for (let i = 0; i < arrayStone.length; i++) {
            array[arrayStone[i].y][arrayStone[i].x] = TYPEMAP.STONE;
        }
        for (let i = 0; i < arrayApple.length; i++) {
            array[arrayApple[i].y][arrayApple[i].x] = TYPEMAP.APPLE;
        }
        return array;
    }

    clone2DArray(arr: number[][]): number[][] {
        return arr.map((subArray) => subArray.slice());
    }
    
}
