import { _decorator, Node, Tween, UIOpacity, Vec3, tween } from 'cc';
import { BaseView } from './BaseView';
const { ccclass, property } = _decorator;

@ccclass('BaseModal')
export class BaseModal extends BaseView {
    @property([Node])
    protected animationNodes: Node[] = [];

    @property(Node)
    protected backdropNode: Node | null = null;

    @property
    protected openAnimationEnabled: boolean = true;

    @property
    protected openAnimationDuration: number = 0.36;

    private readonly _originalScales: Map<Node, Vec3> = new Map();

    onViewShow(): void {
        this.playOpenAnimation();
    }

    onViewHide(): void {
        this.stopOpenAnimation();
    }

    protected playOpenAnimation(): void {
        if (!this.openAnimationEnabled) {
            return;
        }

        this.playBackdropFadeIn();

        const targets = this.getAnimationTargets();
        targets.forEach((target, index) => {
            this.playBounceIn(target, index * 0.035);
        });
    }

    protected stopOpenAnimation(): void {
        this.getAnimationTargets().forEach((target) => {
            Tween.stopAllByTarget(target);
        });

        const opacity = this.backdropNode?.getComponent(UIOpacity);
        if (opacity) {
            Tween.stopAllByTarget(opacity);
        }
    }

    private getAnimationTargets(): Node[] {
        const configuredTargets = this.animationNodes.filter((node) => node?.isValid);
        return configuredTargets.length > 0 ? configuredTargets : [this.node];
    }

    private getOriginalScale(target: Node): Vec3 {
        const cachedScale = this._originalScales.get(target);
        if (cachedScale) {
            return cachedScale;
        }

        const originalScale = target.scale.clone();
        this._originalScales.set(target, originalScale);
        return originalScale;
    }

    private playBounceIn(target: Node, delay: number): void {
        const originalScale = this.getOriginalScale(target);
        const startScale = this.multiplyScale(originalScale, 0.82);
        const peakScale = this.multiplyScale(originalScale, 1.045);

        Tween.stopAllByTarget(target);
        target.setScale(startScale);

        tween(target)
            .delay(delay)
            .to(this.openAnimationDuration * 0.58, { scale: peakScale }, { easing: 'backOut' })
            .to(this.openAnimationDuration * 0.24, { scale: this.multiplyScale(originalScale, 0.985) }, { easing: 'sineOut' })
            .to(this.openAnimationDuration * 0.18, { scale: originalScale }, { easing: 'sineOut' })
            .start();
    }

    private playBackdropFadeIn(): void {
        if (!this.backdropNode?.isValid) {
            return;
        }

        const opacity = this.backdropNode.getComponent(UIOpacity) ?? this.backdropNode.addComponent(UIOpacity);
        Tween.stopAllByTarget(opacity);
        opacity.opacity = 0;

        tween(opacity)
            .to(0.18, { opacity: 255 }, { easing: 'sineOut' })
            .start();
    }

    private multiplyScale(scale: Vec3, factor: number): Vec3 {
        return new Vec3(scale.x * factor, scale.y * factor, scale.z);
    }
}
