import { CHECK_FRAGMENT, CHECK_TOUCH, DROP_ALL_FRAGMENT, eventTarget, HAMMER, PLAY_DROP_SOUND, RESET_FRAGMENT, SHAKE_FRAGMENT, SHOW_FOG, SHOW_SLOT_JAR } from "../Events";
import { Global } from "../Global";
import SlotJar from "./SlotJar";

const { ccclass, property } = cc._decorator;

@ccclass
export default class FragmentJarController extends cc.Component {
    @property([Number])
    private slotJarIndex: number[] = [];

    public isDropped: boolean = false;

    private _physicsCollider: cc.PhysicsPolygonCollider = null;
    private _rg: cc.RigidBody = null;
    private _siblingIndex: number = 0;
    private _numberOfBeats = 3;
    private _slotJar: SlotJar = null;

    onLoad() {
        this._slotJar = this.node.getComponentInChildren(SlotJar);
        this._physicsCollider = this.node.getComponent(cc.PhysicsPolygonCollider);
        this._rg = this.node.getComponent(cc.RigidBody);
        this._siblingIndex = this.node.getSiblingIndex();

        this.reset();

        eventTarget.on(CHECK_TOUCH, this.checkTouch, this);
        eventTarget.on(RESET_FRAGMENT, this.reset, this);
        eventTarget.on(DROP_ALL_FRAGMENT, this.dropAllFragment, this);
        eventTarget.on(SHAKE_FRAGMENT, this.shakeFragment, this);
    }

    public reset() {
        this._physicsCollider.enabled = false;
        this._rg.type = cc.RigidBodyType.Static;
        this.node.angle = 0;
        this.node.scale = 1;
        this.node.setSiblingIndex(this._siblingIndex);
        this.isDropped = false;
        this._numberOfBeats = 3;
    }

    public shakeFragment() {
        if (this.isDropped) {
            return;
        }

        cc.tween(this.node)
            .repeat(2, cc.tween(this.node)
                .by(0.05, { position: cc.v3(-10, -10) })
                .by(0.05, { position: cc.v3(10, 10) })
            )
            .start();
    }

    private checkTouch(point: cc.Vec2) {
        if (this.isDropped) {
            return;
        }
        const jarPos = this.node.parent.position;
        const pos = point.clone().subtract(cc.v2(jarPos.x, jarPos.y)).subtract(this._physicsCollider.offset);

        const isInside = cc.Intersection.pointInPolygon(pos, this._physicsCollider.points);

        if (!isInside) {
            return;
        }

        this._numberOfBeats--;

        eventTarget.emit(HAMMER, point);

        this.scheduleOnce(() => {
            eventTarget.emit(SHOW_SLOT_JAR, this.slotJarIndex, 3 - this._numberOfBeats);
            this.node.scale = 1 - 0.02 * (3 - this._numberOfBeats);
        }, 0.5);

        if (this._numberOfBeats == 1) {
            eventTarget.emit(SHOW_FOG, this.node.position);
        }

        if (this._numberOfBeats > 0) {
            return;
        }

        this.dropFragment();
    }

    private dropAllFragment() {
        if (this.isDropped) {
            return;
        }

        this._slotJar.showSlots(3);

        this.dropFragment();
    }

    private dropFragment() {
        if (this.isDropped) {
            return;
        }

        this.isDropped = true;
        const pos = this.node.position;
        eventTarget.emit(CHECK_FRAGMENT, this.node);
        cc.Tween.stopAllByTarget(this.node);

        cc.tween(this.node)
            .delay(0.5)
            .repeat(4, cc.tween(this.node)
                .by(Global.getRandomTimeSkew(), { position: cc.v3(-5, -5) })
                .by(Global.getRandomTimeSkew(), { position: cc.v3(5, 5) })
            )
            .call(() => {
                eventTarget.emit(PLAY_DROP_SOUND);
                this.node.setSiblingIndex(-1);
            })
            .call(() => {
                this._physicsCollider.enabled = true;
                this._rg.type = cc.RigidBodyType.Dynamic;
                this._physicsCollider.enabled = false;
                this._rg.gravityScale = 15;
            })
            .delay(0.4)
            .call(() => this._physicsCollider.enabled = true)
            .delay(0.6)
            .to(0, { scale: 1 })
            .start();
    }
}
