const { ccclass, property } = cc._decorator;

@ccclass
export default class Test extends cc.Component {

    private circle1: cc.Node;
    private rect1: cc.Node;
    private circle2: cc.Node;

    private debug: cc.Graphics;

    protected start(): void {
        this.circle1 = this.node.getChildByName("circle1");
        this.rect1 = this.node.getChildByName("rect1");
        this.circle2 = this.node.getChildByName("circle2");
        this.debug = this.node.getChildByName("debug").getComponent(cc.Graphics);

        this.rect1.width = 20 + Math.random() * 300;
        this.rect1.height = 20 + Math.random() * 300;
        this.circle2.width = this.circle2.height = 50 + Math.random() * 500;

        let oldP: cc.Vec2;
        this.circle2.on(cc.Node.EventType.TOUCH_START, (evt: cc.Event.EventTouch) => {
            oldP = evt.getLocation();
        });
        this.circle2.on(cc.Node.EventType.TOUCH_MOVE, (evt: cc.Event.EventTouch) => {
            const p = evt.getLocation();
            this.circle2.x += p.x - oldP.x;
            this.circle2.y += p.y - oldP.y;
            oldP = p;

            this.circle2.color = cc.Color.GREEN;
            const r1 = this.circle1.width / 2;
            const r2 = this.circle2.width / 2;
            const dx = this.circle2.x - this.circle1.x;
            const dy = this.circle2.y - this.circle1.y;
            if (dx * dx + dy * dy > (r1 + r2) * (r1 + r2)) {
                this.circle1.color = cc.Color.BLUE;
            } else {
                this.circle1.color = cc.Color.RED;
                this.circle2.color = cc.Color.RED;
            }

            this.debug.clear();
            this.debug.circle(this.circle2.x, this.circle2.y, 4);
            if (this.circleHitRect(this.circle2.x, this.circle2.y, r2, this.rect1.x - this.rect1.width / 2, this.rect1.y + this.rect1.height / 2, this.rect1.x + this.rect1.width / 2, this.rect1.y - this.rect1.height / 2)) {
                this.rect1.color = cc.Color.RED;
                this.circle2.color = cc.Color.RED;
            } else {
                this.rect1.color = cc.Color.BLUE;
            }
            this.debug.stroke();
        });
    }

    private circleHitRect(px: number, py: number, radius: number, l: number, t: number, r: number, b: number): boolean {
        if (this.debug_点p在矩形ltrb里(px, py, l - radius, t + radius, r + radius, b - radius)) {
            if (
                this.debug_圆心p在矩形ltrb里并且点q不在圆里(px, py, radius, l - radius, t + radius, l, t, l, t) ||
                this.debug_圆心p在矩形ltrb里并且点q不在圆里(px, py, radius, l - radius, b, l, b - radius, l, b) ||
                this.debug_圆心p在矩形ltrb里并且点q不在圆里(px, py, radius, r, t + radius, r + radius, t, r, t) ||
                this.debug_圆心p在矩形ltrb里并且点q不在圆里(px, py, radius, r, b, r + radius, b - radius, r, b)
            ) {
                return false;
            }
            return true;
        }
        return false;
    }

    private debug_点p在矩形ltrb里(px: number, py: number, l: number, t: number, r: number, b: number): boolean {
        if (this.点p在矩形ltrb里(px, py, l, t, r, b)) {
            this.debug.rect(l, b, r - l, t - b);
            return true;
        }
        return false;
    }
    private debug_圆心p在矩形ltrb里并且点q不在圆里(px: number, py: number, radius: number, l: number, t: number, r: number, b: number, qx: number, qy: number): boolean {
        if (this.圆心p在矩形ltrb里并且点q不在圆里(px, py, radius, l, t, r, b, qx, qy)) {
            this.debug.circle(qx, qy, 2);
            this.debug.rect(l, b, r - l, t - b);
            return true;
        }
        return false;
    }

    private 点p在矩形ltrb里(px: number, py: number, l: number, t: number, r: number, b: number): boolean {
        return px > l && px < r && py > b && py < t;
    }
    private 圆心p在矩形ltrb里并且点q不在圆里(px: number, py: number, radius: number, l: number, t: number, r: number, b: number, qx: number, qy: number): boolean {
        if (this.点p在矩形ltrb里(px, py, l, t, r, b)) {
            const dx = qx - px;
            const dy = qy - py;
            return dx * dx + dy * dy >= radius * radius;
        }
        return false;
    }

}
