import { _decorator, Node, EditBox, instantiate, Vec3, Button, Label, Sprite, SpriteFrame, AudioClip, AudioSource, Prefab } from 'cc';
import { BaseView } from 'db://assets/scripts/core/BaseView';
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
import { StaminaManager } from 'db://assets/scripts/utils/StaminaManager';
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
import { AuthManager } from 'db://assets/scripts/utils/AuthManager';
import { RuntimeLevelConfig } from 'db://assets/scripts/types/LevelTypes';
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
import { PassModal } from 'db://assets/prefabs/PassModal';
import { WrongModal } from 'db://assets/prefabs/WrongModal';
import { TimeoutModal } from 'db://assets/prefabs/TimeoutModal';
import { StaminaInfo, NextLevelData } from 'db://assets/scripts/types/ApiTypes';
import { AchievementTitleManager } from 'db://assets/scripts/utils/AchievementTitleManager';
const { ccclass, property } = _decorator;

/**
 * 关卡页面组件
 * 继承 BaseView，实现页面生命周期
 * 关卡流程由服务端 NextLevelData 驱动，客户端不再维护关卡列表
 */
@ccclass('PageLevel')
export class PageLevel extends BaseView {
    /** 静态常量：零位置 */
    private static readonly ZERO_POS = new Vec3(0, 0, 0);

    /** 默认体力上限，服务端未返回 max 时使用 */
    private static readonly DEFAULT_STAMINA_MAX = 50;

    /** 答案正确后展示包袱答案的停留时间 */
    private static readonly PASS_MODAL_DELAY_MS = 2000;

    // ========== 节点引用 ==========
    @property(Node)
    inputLayout: Node | null = null;

    @property(Node)
    punchLayout: Node | null = null;

    @property(Node)
    submitButton: Node | null = null;

    @property(Node)
    inputTemplate: Node | null = null;

    @property(Node)
    actionNode: Node | null = null;

    @property(Node)
    iconSetting: Node | null = null;

    @property(Node)
    tipsLayout: Node | null = null;

    @property(Node)
    mainImage: Node | null = null;

    @property(Node)
    mainImage2: Node | null = null;

    @property(Label)
    image1DescLabel: Label | null = null;

    @property(Label)
    image2DescLabel: Label | null = null;

    @property(Node)
    tipsItem1: Node | null = null;

    @property(Node)
    tipsItem2: Node | null = null;

    @property(Node)
    tipsItem3: Node | null = null;

    @property(Node)
    unLockTipsBtn: Node | null = null;

    @property(Node)
    addTimeBtn: Node | null = null;

    @property(Label)
    clockLabel: Label | null = null;

    /** 体力值显示标签（prefab 中序列化名为 liveLabel，保持兼容） */
    @property(Label)
    liveLabel: Label | null = null;

    /** 关卡标题标签，显示为"第 N 关" */
    @property(Label)
    titleLevelLabel: Label | null = null;

    // ========== 配置属性 ==========
    @property(AudioClip)
    clickAudio: AudioClip | null = null;

    @property(AudioClip)
    successAudio: AudioClip | null = null;

    @property(AudioClip)
    failAudio: AudioClip | null = null;

    @property(Prefab)
    passModalPrefab: Prefab | null = null;

    @property(Prefab)
    wrongModalPrefab: Prefab | null = null;

    @property(Prefab)
    timeoutModalPrefab: Prefab | null = null;

    // ========== 内部状态 ==========
    /** 当前创建的输入框节点数组 */
    private _inputNodes: Node[] = [];

    /** InputLayout 中默认放置的输入框模板节点 */
    private _inputTemplateNode: Node | null = null;

    /** 当前创建的包袱展示块节点数组 */
    private _punchBlockNodes: Node[] = [];

    /** punchLayout 中默认放置的展示块模板节点 */
    private _punchBlockTemplateNode: Node | null = null;

    /** 是否正在同步输入格内容，避免设置文本时重复触发事件 */
    private _isSyncingInputText: boolean = false;

    /** 最近一次自动提交的答案，避免填满后重复提交同一内容 */
    private _lastAutoSubmittedAnswer: string = '';

    /** 倒计时剩余秒数 */
    private _countdown: number = 60;

    /** 关卡开始时间戳（ms），用于准确计算耗时 */
    private _levelStartTime: number = 0;

    /** 倒计时是否结束 */
    private _isTimeUp: boolean = false;

    /** 当前关卡配置 */
    private _currentConfig: RuntimeLevelConfig | null = null;

    /** 是否正在切换关卡（防止重复提交） */
    private _isTransitioning: boolean = false;

    /** 是否正在解锁提示（防止双击重复触发） */
    private _isUnlocking: boolean = false;

    /** 下一个待解锁的线索序号（2 或 3），超过 3 表示全部已解锁 */
    private _nextClueIndex: number = 2;

    /** 通关弹窗实例 */
    private _passModalNode: Node | null = null;

    /** 本次通关弹窗使用的已通关数量 */
    private _passModalCompletedLevelCount: number | null = null;

    /** 错误弹窗实例 */
    private _wrongModalNode: Node | null = null;

    /** 超时弹窗实例 */
    private _timeoutModalNode: Node | null = null;

    /** 是否处于分享挑战模式 */
    private _isShareMode: boolean = false;

    /** 体力恢复倒计时定时器 */
    private _staminaTimerId: ReturnType<typeof setInterval> | null = null;

    // ========== 关卡驱动状态（NextLevel 驱动） ==========

    /** 当前关卡 ID */
    private _currentLevelId: string = '';

    /** 当前关卡编号（仅显示用，来自 NextLevelData.level） */
    private _currentLevelNumber: number = 0;

    /** 下一关数据（来自 complete 接口返回），点击"下一关"时使用 */
    private _nextLevelData: NextLevelData | null = null;

    /** 分享模式下的关卡索引（仅分享模式使用） */
    private _shareLevelIndex: number = 0;

    /**
     * 页面首次加载时调用
     */
    onViewLoad(): void {
        console.log('[PageLevel] onViewLoad');

        const params = this.getParams();
        this._isShareMode = params?.shareMode === true;

        if (this._isShareMode) {
            this._shareLevelIndex = 0;
            console.log('[PageLevel] 进入分享挑战模式');
        } else {
            // 从 AuthManager 获取首关数据（由 PageLoading → game-data 提供）
            const nextLevel = AuthManager.instance.nextLevel;
            if (nextLevel) {
                this._currentLevelId = nextLevel.id;
                this._currentLevelNumber = nextLevel.level;
                console.log(`[PageLevel] 进入关卡: 第 ${nextLevel.level} 关 (${nextLevel.id})`);
            } else {
                console.warn('[PageLevel] 没有可用关卡');
            }
        }

        this.updateStaminaLabel();
        this.initIconSetting();
        this.initUnlockButtons();
        this.initSubmitButton();

        // 异步加载关卡资源并调用进入关卡接口，完成后启动倒计时
        this._enterAndInitLevel().catch(err => {
            console.error('[PageLevel] 进入关卡失败:', err);
        });
    }

    /**
     * 页面每次显示时调用
     */
    onViewShow(): void {
        console.log('[PageLevel] onViewShow');
        this.updateStaminaLabel();
        this._startStaminaRecoverTimer();
    }

    /**
     * 页面隐藏时调用
     */
    onViewHide(): void {
        console.log('[PageLevel] onViewHide');
        this._stopStaminaRecoverTimer();
    }

    /**
     * 页面销毁时调用
     */
    onViewDestroy(): void {
        console.log('[PageLevel] onViewDestroy');
        this.clearInputNodes();
        this.clearPunchBlocks();
        this.stopCountdown();
        this._closePassModal();
        this._closeWrongModal();
        this._closeTimeoutModal();
        this._stopStaminaRecoverTimer();

        // 清理事件监听
        this.iconSetting?.off(Node.EventType.TOUCH_END, this.onIconSettingClick, this);
        this.unLockTipsBtn?.off(Node.EventType.TOUCH_END);
        this.addTimeBtn?.off(Node.EventType.TOUCH_END);
        this.submitButton?.off(Node.EventType.TOUCH_END, this.onSubmitAnswer, this);
    }

    /**
     * 进入关卡并初始化
     * 1. 加载关卡图片资源（从缓存或 NextLevelData）
     * 2. 调用进入关卡接口（消耗体力，获取答案和线索）
     * 3. 启动倒计时
     */
    private async _enterAndInitLevel(): Promise<void> {
        let config: RuntimeLevelConfig | null = null;

        if (this._isShareMode) {
            // 分享模式：使用 ShareManager 的关卡数据
            config = await ShareManager.instance.ensureShareLevelReady(this._shareLevelIndex);
        } else {
            // 正常模式：先尝试从缓存获取（PageLoading 初始化时已加载首关）
            config = LevelDataManager.instance.getLevelConfig(this._currentLevelId);

            if (!config) {
                // 缓存未命中，从 nextLevel 数据加载（complete 返回的下一关）
                const nextLevelData = this._nextLevelData ?? AuthManager.instance.nextLevel;
                if (nextLevelData && nextLevelData.id === this._currentLevelId) {
                    console.log(`[PageLevel] 关卡 ${this._currentLevelId} 资源未缓存，开始加载...`);
                    config = await LevelDataManager.instance.ensureLevelReady(nextLevelData);
                }
            }
        }

        if (!config) {
            console.warn(`[PageLevel] 没有找到关卡配置，ID: ${this._currentLevelId}`);
            return;
        }

        // 非分享模式下，调用进入关卡接口获取答案和线索
        if (!this._isShareMode) {
            const enterData = await StaminaManager.instance.enterLevel(this._currentLevelId);
            if (!enterData) {
                // 进入关卡失败（可能是体力不足）
                const stamina = StaminaManager.instance.getStamina();
                if (stamina.current <= 0) {
                    ToastManager.show('体力不足，请等待恢复');
                    this._startStaminaRecoverTimer();
                } else {
                    ToastManager.show('进入关卡失败，请重试');
                }
                this.updateStaminaLabel();
                return;
            }

            // 提示用户消耗体力
            ToastManager.show(`消耗1点体力，剩余 ${enterData.stamina.current}/${this._getStaminaMax(enterData.stamina)}`);

            // 用 enter 接口返回的数据更新关卡配置（填充答案和线索）
            LevelDataManager.instance.updateLevelDetails(
                this._currentLevelId,
                {
                    answer: enterData.answer,
                    image1Description: enterData.image1Description,
                    image2Description: enterData.image2Description,
                    punchline: enterData.punchline,
                    hint1: enterData.hint1,
                    hint2: enterData.hint2,
                    hint3: enterData.hint3,
                }
            );

            // 重新获取更新后的配置
            config = LevelDataManager.instance.getLevelConfig(this._currentLevelId);
            if (!config) {
                console.error('[PageLevel] 更新关卡详情后获取配置失败');
                return;
            }

            // 更新体力显示
            this.updateStaminaLabel();

            // 预加载下一关图片（enter 返回的 preloadNextLevel）
            if (enterData.preloadNextLevel) {
                LevelDataManager.instance.preloadLevel(enterData.preloadNextLevel);
            }
        }

        console.log(`[PageLevel] 初始化关卡 第${this._currentLevelNumber}关: ${config.name}`);
        this._applyLevelConfig(config);
        this.startCountdown();
    }

    /**
     * 应用关卡配置（通用初始化逻辑）
     */
    private _applyLevelConfig(config: RuntimeLevelConfig): void {
        this._currentConfig = config;

        // 重置关卡切换状态，允许再次提交
        this._isTransitioning = false;

        // 重置倒计时状态
        this._isTimeUp = false;
        this._countdown = config.timeLimit ?? 60;

        // 设置主图（图片1）
        this.setMainImage(config.spriteFrame1);

        // 设置图片2
        this.setMainImage2(config.spriteFrame2);

        // 设置图片描述
        this.setImageDescriptions(config.image1Description, config.image2Description);

        // 设置关卡标题
        this.updateTitleLevelLabel();

        // 隐藏包袱答案，通关后再按 punchline 展示
        this.hidePunchline();

        // 设置线索1（默认解锁，如果有的话）
        if (config.clue1) {
            this.setClue(1, config.clue1);
        }

        // 重置线索解锁进度
        this._nextClueIndex = 2;

        // 线索2、3 保持显示，写入"待解锁"占位文案
        this.setClue(2, '待解锁');
        this.setClue(3, '待解锁');

        // 显示解锁按钮（单个统一按钮）
        this.showUnlockButton();

        // 根据答案字数创建输入格
        if (config.answer) {
            this.createInputBlocks(config.answer);
        }

        // 更新倒计时显示
        this.updateClockLabel();

        // 分享模式下预加载下一关
        if (this._isShareMode) {
            const nextIndex = this._shareLevelIndex + 1;
            if (nextIndex < ShareManager.instance.getShareLevelCount()) {
                ShareManager.instance.ensureShareLevelReady(nextIndex).catch(() => {});
            }
        }
        // 正常模式的预加载在 enter 返回 preloadNextLevel 时已处理

        console.log(`[PageLevel] 初始化关卡 第${this._currentLevelNumber}关, 答案长度: ${Array.from(config.answer ?? '').length}`);
    }

    /**
     * 根据答案字数创建输入格
     */
    private createInputBlocks(answer: string): void {
        if (!this.inputLayout) {
            console.error('[PageLevel] inputLayout 未设置');
            return;
        }

        const chars = Array.from(answer);
        const template = this.getInputTemplateNode();
        if (!template) {
            console.error('[PageLevel] InputLayout 下未找到默认 Input 节点');
            return;
        }
        if (this.inputTemplate && this.inputTemplate !== template) {
            this.inputTemplate.active = false;
        }

        this.clearInputNodes();
        this.removeUnexpectedInputLayoutChildren(template);
        this._lastAutoSubmittedAnswer = '';

        for (let i = 0; i < chars.length; i++) {
            const inputNode = i === 0 ? template : instantiate(template);
            inputNode.active = true;
            inputNode.name = `Input_${i + 1}`;
            inputNode.setPosition(PageLevel.ZERO_POS);

            const editBox = inputNode.getComponent(EditBox);
            if (editBox) {
                editBox.placeholder = '';
                editBox.maxLength = chars.length;
                editBox.string = '';
                editBox.node.on(EditBox.EventType.EDITING_DID_BEGAN, this.onInputEditingBegan, this);
                editBox.node.on(EditBox.EventType.TEXT_CHANGED, this.onInputTextChanged, this);
                editBox.node.on(EditBox.EventType.EDITING_DID_ENDED, this.onInputEditingEnded, this);
            }

            if (inputNode.parent !== this.inputLayout) {
                this.inputLayout.addChild(inputNode);
            }
            this._inputNodes.push(inputNode);
        }

        console.log(`[PageLevel] 创建输入格，答案长度: ${chars.length}`);
    }

    /**
     * 清理所有输入框节点
     */
    private clearInputNodes(): void {
        const template = this.getInputTemplateNode();

        for (const node of this._inputNodes) {
            if (node.isValid) {
                const editBox = node.getComponent(EditBox);
                if (editBox) {
                    editBox.node.off(EditBox.EventType.EDITING_DID_BEGAN, this.onInputEditingBegan, this);
                    editBox.node.off(EditBox.EventType.TEXT_CHANGED, this.onInputTextChanged, this);
                    editBox.node.off(EditBox.EventType.EDITING_DID_ENDED, this.onInputEditingEnded, this);
                    editBox.string = '';
                }

                if (node === template) {
                    node.active = false;
                } else {
                    node.removeFromParent();
                    node.destroy();
                }
            }
        }
        this._inputNodes = [];
    }

    private getInputTemplateNode(): Node | null {
        if (this._inputTemplateNode?.isValid) return this._inputTemplateNode;

        this._inputTemplateNode = this.inputLayout?.children.find(node => !!node.getComponent(EditBox)) ?? this.inputTemplate ?? null;
        return this._inputTemplateNode;
    }

    private removeUnexpectedInputLayoutChildren(template: Node): void {
        if (!this.inputLayout) return;

        for (const child of [...this.inputLayout.children]) {
            if (child !== template) {
                child.removeFromParent();
                child.destroy();
            }
        }
    }

    /**
     * 获取所有输入框的值
     */
    getInputValues(): string[] {
        if (this._inputNodes.length === 0) return [];
        return this._inputNodes.map(node => (node.getComponent(EditBox)?.string ?? '').trim());
    }

    /**
     * 获取拼接后的答案字符串
     */
    getAnswer(): string {
        if (this._inputNodes.length === 0) return '';
        return this.getInputValues().join('').trim();
    }

    // ========== EditBox 事件回调 ==========

    /**
     * 输入框开始编辑时，把当前所有格子的内容合并到当前输入框里
     */
    private onInputEditingBegan(editBox: EditBox): void {
        if (this._isSyncingInputText) return;

        const inputIndex = this._inputNodes.findIndex(node => node === editBox.node);
        if (inputIndex < 0) return;

        const answer = this.getAnswer();
        this._isSyncingInputText = true;

        try {
            for (let i = 0; i < this._inputNodes.length; i++) {
                const itemEditBox = this._inputNodes[i].getComponent(EditBox);
                if (itemEditBox) {
                    itemEditBox.string = i === inputIndex ? answer : '';
                }
            }
        } finally {
            this._isSyncingInputText = false;
        }
    }

    /**
     * 输入框文本变化回调
     */
    private onInputTextChanged(_editBox: EditBox): void {
        this._lastAutoSubmittedAnswer = '';
    }

    /**
     * 输入框编辑结束回调
     */
    private onInputEditingEnded(editBox: EditBox): void {
        if (this._isSyncingInputText) return;

        const inputIndex = this._inputNodes.findIndex(node => node === editBox.node);
        if (inputIndex < 0) return;

        this.distributeInputText(editBox.string);
        this.tryAutoSubmitAnswer();
    }

    private distributeInputText(text: string): void {
        const chars = Array.from(text);
        this._isSyncingInputText = true;

        try {
            for (let i = 0; i < this._inputNodes.length; i++) {
                const editBox = this._inputNodes[i].getComponent(EditBox);
                if (editBox) {
                    editBox.string = chars[i] ?? '';
                }
            }
        } finally {
            this._isSyncingInputText = false;
        }
    }

    private clearInputText(): void {
        this._isSyncingInputText = true;

        try {
            for (const node of this._inputNodes) {
                const editBox = node.getComponent(EditBox);
                if (editBox) {
                    editBox.string = '';
                }
            }
            this._lastAutoSubmittedAnswer = '';
        } finally {
            this._isSyncingInputText = false;
        }
    }

    private tryAutoSubmitAnswer(): void {
        if (!this._currentConfig || this._isTransitioning) return;

        const values = this.getInputValues();
        const isFilled = values.length === Array.from(this._currentConfig.answer ?? '').length && values.every(value => value.length === 1);
        if (!isFilled) {
            this._lastAutoSubmittedAnswer = '';
            return;
        }

        const answer = values.join('');
        if (answer === this._lastAutoSubmittedAnswer) return;

        this._lastAutoSubmittedAnswer = answer;
        this.onSubmitAnswer();
    }

    // ========== IconSetting 按钮相关 ==========

    /**
     * 初始化 IconSetting 按钮事件
     */
    private initIconSetting(): void {
        if (!this.iconSetting) {
            console.warn('[PageLevel] iconSetting 节点未设置');
            return;
        }

        const button = this.iconSetting.getComponent(Button);
        if (!button) {
            console.warn('[PageLevel] iconSetting 节点缺少 Button 组件');
            return;
        }

        this.iconSetting.on(Node.EventType.TOUCH_END, this.onIconSettingClick, this);
        console.log('[PageLevel] IconSetting 按钮事件已绑定');
    }

    /**
     * IconSetting 按钮点击回调
     */
    private onIconSettingClick(): void {
        console.log('[PageLevel] IconSetting 点击，返回主页');
        this.playClickSound();

        // 分享模式下栈中没有 PageHome，需要清除分享状态并直接打开首页
        if (this._isShareMode) {
            ShareManager.instance.clearShareMode();
            ViewManager.instance.replace('PageHome');
        } else {
            ViewManager.instance.back();
        }
    }

    // ========== 线索相关方法 ==========

    /**
     * 获取线索节点
     */
    private getTipsItem(index: number): Node | null {
        switch (index) {
            case 1: return this.tipsItem1;
            case 2: return this.tipsItem2;
            case 3: return this.tipsItem3;
            default: return null;
        }
    }

    /**
     * 设置线索内容
     */
    private setClue(index: number, content: string): void {
        const tipsItem = this.getTipsItem(index);
        if (!tipsItem) return;

        const label = this.getTipsLabel(tipsItem);
        if (label) {
            label.string = `提示${index}：${content}`;
            console.log(`[PageLevel] 设置线索${index}: ${content}`);
        }
    }

    private getTipsLabel(tipsItem: Node): Label | null {
        const directLabel = tipsItem.getChildByName('TipsLabel')?.getComponent(Label);
        if (directLabel) return directLabel;

        return tipsItem.getChildByName('Content')?.getChildByName('TipsLabel')?.getComponent(Label) ?? null;
    }

    /**
     * 显示线索
     */
    private showClue(index: number): void {
        const tipsItem = this.getTipsItem(index);
        if (tipsItem) {
            tipsItem.active = true;
            console.log(`[PageLevel] 显示线索${index}`);
        }
    }

    /**
     * 隐藏线索
     */
    private hideClue(index: number): void {
        const tipsItem = this.getTipsItem(index);
        if (tipsItem) {
            tipsItem.active = false;
            console.log(`[PageLevel] 隐藏线索${index}`);
        }
    }

    /**
     * 显示解锁按钮
     */
    private showUnlockButton(_index?: number): void {
        if (this.unLockTipsBtn) {
            this.unLockTipsBtn.active = true;
            console.log('[PageLevel] 显示解锁按钮');
        }
    }

    /**
     * 隐藏解锁按钮
     */
    private hideUnlockButton(_index?: number): void {
        if (this.unLockTipsBtn) {
            this.unLockTipsBtn.active = false;
            console.log('[PageLevel] 隐藏解锁按钮');
        }
    }

    /**
     * 初始化解锁按钮事件
     */
    private initUnlockButtons(): void {
        if (this.unLockTipsBtn) {
            this.unLockTipsBtn.on(Node.EventType.TOUCH_END, this.onUnlockClue, this);
        }

        if (this.addTimeBtn) {
            this.addTimeBtn.on(Node.EventType.TOUCH_END, this.onAddTime, this);
        }

        console.log('[PageLevel] 解锁按钮事件已绑定');
    }

    /**
     * 初始化提交按钮事件
     */
    private initSubmitButton(): void {
        if (!this.submitButton) {
            console.warn('[PageLevel] submitButton 节点未设置');
            return;
        }

        this.submitButton.on(Node.EventType.TOUCH_END, this.onSubmitAnswer, this);
        console.log('[PageLevel] 提交按钮事件已绑定');
    }

    /**
     * 点击解锁线索（顺序解锁：先线索2，再线索3；全部解锁后提示已解锁完毕）
     */
    private onUnlockClue(): void {
        // 全部已解锁，提示用户
        if (this._nextClueIndex > 3) {
            ToastManager.show('已解锁完毕');
            return;
        }

        if (!this._currentConfig) return;

        const index = this._nextClueIndex;
        const clueContent = index === 2 ? this._currentConfig.clue2 : this._currentConfig.clue3;
        if (!clueContent) {
            ToastManager.show('该提示暂未配置');
            return;
        }

        this.playClickSound();
        this.setClue(index, clueContent);

        // 推进到下一条待解锁线索
        this._nextClueIndex++;

        // 全部解锁完毕则隐藏按钮
        if (this._nextClueIndex > 3) {
            this.hideUnlockButton();
        }

        console.log(`[PageLevel] 解锁线索${index}`);
    }

    /**
     * 点击增加时间按钮（倒计时增加 60 秒）
     */
    private onAddTime(): void {
        if (this._isTimeUp) {
            ToastManager.show('时间已结束，无法增加');
            return;
        }

        this._countdown += 60;
        this.updateClockLabel();
        this.playClickSound();
        ToastManager.show('已成功增加60秒！');
        console.log(`[PageLevel] 增加60秒倒计时，当前剩余: ${this._countdown}s`);
    }

    // ========== 主图相关方法 ==========

    /**
     * 设置主图（图片1）
     */
    private setMainImage(spriteFrame: SpriteFrame | null): void {
        if (!this.mainImage) return;

        const sprite = this.mainImage.getComponent(Sprite);
        if (sprite && spriteFrame) {
            sprite.spriteFrame = spriteFrame;
            console.log('[PageLevel] 设置主图1');
        }
    }

    /**
     * 设置图片2
     */
    private setMainImage2(spriteFrame: SpriteFrame | null): void {
        if (!this.mainImage2) return;

        const sprite = this.mainImage2.getComponent(Sprite);
        if (sprite && spriteFrame) {
            sprite.spriteFrame = spriteFrame;
            console.log('[PageLevel] 设置主图2');
        }
    }

    /**
     * 设置图片描述文本
     */
    private setImageDescriptions(desc1: string | null, desc2: string | null): void {
        if (this.image1DescLabel) {
            this.image1DescLabel.string = desc1 ?? '';
        }
        if (this.image2DescLabel) {
            this.image2DescLabel.string = desc2 ?? '';
        }
    }

    private updateTitleLevelLabel(): void {
        if (!this.titleLevelLabel) return;

        this.titleLevelLabel.string = `第 ${this._currentLevelNumber} 关`;
    }

    /**
     * 设置谐音梗说明（通关后逐字展示，未通关时传 null 隐藏）
     */
    private setPunchline(punchline: string | null): void {
        if (!this.punchLayout) return;

        const chars = Array.from(punchline ?? '');
        if (chars.length === 0) {
            this.hidePunchline();
            return;
        }

        const template = this.getPunchBlockTemplateNode();
        if (!template) {
            console.error('[PageLevel] punchLayout 下未找到默认 block 节点');
            return;
        }

        this.clearPunchBlocks();
        this.removeUnexpectedPunchLayoutChildren(template);
        this.punchLayout.active = true;

        for (let i = 0; i < chars.length; i++) {
            const blockNode = i === 0 ? template : instantiate(template);
            blockNode.active = true;
            blockNode.name = `block_${i + 1}`;
            blockNode.setPosition(PageLevel.ZERO_POS);

            const label = this.getPunchBlockLabel(blockNode);
            if (label) {
                label.node.active = true;
                label.enabled = true;
                label.string = chars[i];
                console.log(`[PageLevel] 设置包袱块${i + 1}: ${chars[i]}`);
            } else {
                console.warn(`[PageLevel] 包袱块${i + 1} 未找到 Label 组件`);
            }

            if (blockNode.parent !== this.punchLayout) {
                this.punchLayout.addChild(blockNode);
            }
            this._punchBlockNodes.push(blockNode);
        }
    }

    private clearPunchBlocks(): void {
        const template = this.getPunchBlockTemplateNode();

        for (const node of this._punchBlockNodes) {
            if (node.isValid) {
                const label = this.getPunchBlockLabel(node);
                if (label) {
                    label.string = '';
                }

                if (node === template) {
                    node.active = false;
                } else {
                    node.removeFromParent();
                    node.destroy();
                }
            }
        }
        this._punchBlockNodes = [];
    }

    private hidePunchline(): void {
        if (!this.punchLayout) return;

        const template = this.getPunchBlockTemplateNode();
        if (!template) {
            this.punchLayout.active = false;
            return;
        }

        this.clearPunchBlocks();
        this.removeUnexpectedPunchLayoutChildren(template);
        this.punchLayout.active = false;
        template.active = false;
        template.name = 'block';

        const label = this.getPunchBlockLabel(template);
        if (label) {
            label.node.active = true;
            label.enabled = true;
            label.string = '';
        }

        this._punchBlockNodes = [];
    }

    private removeUnexpectedPunchLayoutChildren(template: Node): void {
        if (!this.punchLayout) return;

        for (const child of [...this.punchLayout.children]) {
            if (child !== template) {
                child.removeFromParent();
                child.destroy();
            }
        }
    }

    private getPunchBlockTemplateNode(): Node | null {
        if (this._punchBlockTemplateNode?.isValid) return this._punchBlockTemplateNode;

        this._punchBlockTemplateNode = this.punchLayout?.children[0] ?? null;
        return this._punchBlockTemplateNode;
    }

    private getPunchBlockLabel(blockNode: Node): Label | null {
        return this.findLabelInNode(blockNode);
    }

    private findLabelInNode(node: Node): Label | null {
        const label = node.getComponent(Label);
        if (label) return label;

        for (const child of node.children) {
            const childLabel = this.findLabelInNode(child);
            if (childLabel) return childLabel;
        }

        return null;
    }

    // ========== 音效相关方法 ==========

    /**
     * 播放音效（通用方法）
     */
    private playSound(clip: AudioClip | null): void {
        if (!clip) return;
        const audioSource = this.node.getComponent(AudioSource);
        audioSource?.playOneShot(clip);
    }

    /**
     * 播放点击音效
     */
    private playClickSound(): void {
        this.playSound(this.clickAudio);
    }

    /**
     * 播放成功音效
     */
    private playSuccessSound(): void {
        this.playSound(this.successAudio);
    }

    /**
     * 播放失败音效
     */
    private playFailSound(): void {
        this.playSound(this.failAudio);
    }

    // ========== 倒计时相关方法 ==========

    /**
     * 开始倒计时
     */
    private startCountdown(): void {
        // _countdown 已在 _applyLevelConfig 中根据 timeLimit 设置
        this._isTimeUp = false;
        this._levelStartTime = Date.now();
        this.updateClockLabel();
        this.schedule(this.onCountdownTick, 1);
        console.log(`[PageLevel] 开始倒计时 ${this._countdown} 秒`);
    }

    /**
     * 停止倒计时
     */
    private stopCountdown(): void {
        this.unschedule(this.onCountdownTick);
    }

    /**
     * 倒计时每秒回调
     */
    private onCountdownTick(): void {
        if (this._isTimeUp) return;

        this._countdown--;
        this.updateClockLabel();

        if (this._countdown <= 0) {
            this._isTimeUp = true;
            this.stopCountdown();
            this.onTimeUp();
        }
    }

    /**
     * 更新倒计时显示
     */
    private updateClockLabel(): void {
        if (this.clockLabel) {
            this.clockLabel.string = `${this._countdown}s`;
        }
    }

    /**
     * 倒计时结束
     */
    private onTimeUp(): void {
        console.log('[PageLevel] 倒计时结束！');
        this.playFailSound();
        this._showTimeoutModal();
    }

    // ========== 体力值相关方法 ==========

    /** 上次显示的体力值，用于变更检测 */
    private _lastDisplayedStamina: number = -1;

    /** 上次显示的体力上限，用于变更检测 */
    private _lastDisplayedStaminaMax: number = -1;

    /**
     * 获取体力上限，服务端未返回时使用默认值兜底
     */
    private _getStaminaMax(stamina: StaminaInfo): number {
        return typeof stamina.max === 'number' ? stamina.max : PageLevel.DEFAULT_STAMINA_MAX;
    }

    /**
     * 更新体力值显示（仅值变化时更新 UI）
     */
    private updateStaminaLabel(): void {
        if (this.liveLabel) {
            const stamina = StaminaManager.instance.getStamina();
            const maxStamina = this._getStaminaMax(stamina);
            if (stamina.current !== this._lastDisplayedStamina || maxStamina !== this._lastDisplayedStaminaMax) {
                this.liveLabel.string = `${stamina.current}/${maxStamina}`;
                this._lastDisplayedStamina = stamina.current;
                this._lastDisplayedStaminaMax = maxStamina;
            }
        }
    }

    /**
     * 启动体力恢复倒计时 UI
     */
    private _startStaminaRecoverTimer(): void {
        this._stopStaminaRecoverTimer();

        const stamina = StaminaManager.instance.getStamina();
        const maxStamina = this._getStaminaMax(stamina);
        if (!stamina.nextRecoverAt || stamina.current >= maxStamina) {
            return;
        }

        const targetTime = new Date(stamina.nextRecoverAt).getTime();
        if (isNaN(targetTime)) return;

        this._staminaTimerId = setInterval(() => {
            if (targetTime - Date.now() > 0) return;

            // 恢复一点体力
            const currentStamina = StaminaManager.instance.getStamina();
            const currentMaxStamina = this._getStaminaMax(currentStamina);
            const newCurrent = Math.min(currentStamina.current + 1, currentMaxStamina);
            const newStamina: StaminaInfo = {
                ...currentStamina,
                max: currentMaxStamina,
                current: newCurrent,
                nextRecoverAt: newCurrent < currentMaxStamina
                    ? new Date(Date.now() + 10 * 60 * 1000).toISOString()
                    : null,
            };
            StaminaManager.instance.updateStamina(newStamina);
            this.updateStaminaLabel();

            this._stopStaminaRecoverTimer();

            if (newCurrent < currentMaxStamina) {
                this._startStaminaRecoverTimer();
            }
        }, 1000);
    }

    /**
     * 停止体力恢复倒计时
     */
    private _stopStaminaRecoverTimer(): void {
        if (this._staminaTimerId !== null) {
            clearInterval(this._staminaTimerId);
            this._staminaTimerId = null;
        }
    }

    // ========== 答案提交与关卡切换 ==========

    /**
     * 提交答案
     */
    onSubmitAnswer(): void {
        if (!this._currentConfig) return;
        if (this._isTransitioning) return;

        const userAnswer = this.getAnswer();
        console.log(`[PageLevel] 提交答案: ${userAnswer}, 正确答案: ${this._currentConfig.answer}`);

        if (userAnswer === this._currentConfig.answer) {
            // 答案正确，只播放成功音效（不播放点击音效，避免重合）
            this.showSuccess();
        } else {
            // 答案错误
            this.showError();
        }
    }

    /**
     * 显示成功提示并上报通关
     */
    private async showSuccess(): Promise<void> {
        console.log('[PageLevel] 答案正确！');

        // 标记正在切换关卡，防止重复提交
        this._isTransitioning = true;

        // 停止倒计时
        this.stopCountdown();

        // 播放成功音效
        this.playSuccessSound();

        // 通关后根据 punchline 字数重建包袱答案块
        this.setPunchline(this._currentConfig?.punchline ?? null);

        const levelId = this._currentConfig?.id ?? '';
        const timeSpent = Math.max(0, Math.round((Date.now() - this._levelStartTime) / 1000));

        this.reportLevelCompleted(levelId, timeSpent);
        await this.delay(PageLevel.PASS_MODAL_DELAY_MS);

        // 显示通关弹窗
        this._showPassModal();
    }

    /**
     * 上报通关并获取下一关数据
     */
    private reportLevelCompleted(levelId: string, timeSpent: number): void {
        if (!this._isShareMode) {
            // 乐观更新通关计数（用于称号展示）
            AuthManager.instance.addCompletedLevelCount();
            this._passModalCompletedLevelCount = AuthManager.instance.completedLevelCount;

            void StaminaManager.instance.completeLevel(levelId, timeSpent).then((result) => {
                if (result) {
                    // 保存 complete 返回的下一关数据
                    this._nextLevelData = result.nextLevel;

                    if (!result.firstClear) {
                        // 非首次通关，回退乐观更新
                        AuthManager.instance.addCompletedLevelCount(-1);
                        this._passModalCompletedLevelCount = AuthManager.instance.completedLevelCount;
                    }
                    console.log(`[PageLevel] 通关上报成功，首次通关: ${result.firstClear}, 有下一关: ${!!result.nextLevel}`);
                }
            });
            return;
        }

        this._passModalCompletedLevelCount = null;
        // fire-and-forget: errors are logged inside reportLevelProgress
        void ShareManager.instance.reportLevelProgress(levelId, true, timeSpent);
    }

    private delay(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    /**
     * 显示通关弹窗
     * 将弹窗添加到 Canvas 根节点下（而非 PageLevel 子节点）
     * 这样 Widget 可以正确对齐到全屏
     */
    private _showPassModal(): void {
        if (!this.passModalPrefab) {
            console.warn('[PageLevel] passModalPrefab 未设置');
            return;
        }

        // 如果弹窗已显示，不再重复创建
        if (this._passModalNode && this._passModalNode.isValid) {
            return;
        }

        // 实例化弹窗
        const modalNode = instantiate(this.passModalPrefab);
        modalNode.setPosition(PageLevel.ZERO_POS);
        modalNode.setSiblingIndex(PassModal.MODAL_Z_INDEX);

        // 找到 Canvas 根节点并添加弹窗
        const canvasNode = this.node.parent;
        if (canvasNode) {
            canvasNode.addChild(modalNode);
        } else {
            this.node.addChild(modalNode);
        }
        this._passModalNode = modalNode;

        // 获取 PassModal 组件并设置回调
        const passModal = modalNode.getComponent(PassModal);
        if (passModal) {
            passModal.setParams({
                levelIndex: this._currentLevelNumber,
                titleInfo: AchievementTitleManager.getTitleInfo(this._getPassModalCompletedLevelCount())
            });
            passModal.setCallbacks({
                onNextLevel: () => {
                    this._closePassModal();
                    this.goToNextLevel();
                },
                onShare: () => {
                    // 分享后不关闭弹窗，用户可继续点击下一关
                    console.log('[PageLevel] 分享完成');
                }
            });
            // 手动调用 onViewLoad 和 onViewShow
            passModal.onViewLoad();
            passModal.onViewShow();
        }

        console.log('[PageLevel] 显示通关弹窗');
    }

    private _getPassModalCompletedLevelCount(): number {
        return this._passModalCompletedLevelCount ?? AuthManager.instance.completedLevelCount;
    }

    /**
     * 关闭通关弹窗
     */
    private _closePassModal(): void {
        if (this._passModalNode && this._passModalNode.isValid) {
            this._passModalNode.destroy();
            this._passModalNode = null;
            console.log('[PageLevel] 关闭通关弹窗');
        }
    }

    /**
     * 显示错误弹窗
     */
    private _showWrongModal(): void {
        if (!this.wrongModalPrefab) {
            console.warn('[PageLevel] wrongModalPrefab 未设置');
            return;
        }

        // 如果弹窗已显示，不再重复创建
        if (this._wrongModalNode && this._wrongModalNode.isValid) {
            return;
        }

        const modalNode = instantiate(this.wrongModalPrefab);
        modalNode.setPosition(PageLevel.ZERO_POS);
        modalNode.setSiblingIndex(WrongModal.MODAL_Z_INDEX);

        const canvasNode = this.node.parent;
        if (canvasNode) {
            canvasNode.addChild(modalNode);
        } else {
            this.node.addChild(modalNode);
        }
        this._wrongModalNode = modalNode;

        const wrongModal = modalNode.getComponent(WrongModal);
        if (wrongModal) {
            wrongModal.setCallbacks({
                onContinue: () => {
                    this._closeWrongModal();
                    this.clearInputText();
                }
            });
            wrongModal.onViewLoad();
            wrongModal.onViewShow();
        }

        console.log('[PageLevel] 显示错误弹窗');
    }

    /**
     * 关闭错误弹窗
     */
    private _closeWrongModal(): void {
        if (this._wrongModalNode && this._wrongModalNode.isValid) {
            this._wrongModalNode.destroy();
            this._wrongModalNode = null;
            console.log('[PageLevel] 关闭错误弹窗');
        }
    }

    /**
     * 显示超时弹窗
     */
    private _showTimeoutModal(): void {
        if (!this.timeoutModalPrefab) {
            console.warn('[PageLevel] timeoutModalPrefab 未设置');
            return;
        }

        // 如果弹窗已显示，不再重复创建
        if (this._timeoutModalNode && this._timeoutModalNode.isValid) {
            return;
        }

        const modalNode = instantiate(this.timeoutModalPrefab);
        modalNode.setPosition(PageLevel.ZERO_POS);
        modalNode.setSiblingIndex(TimeoutModal.MODAL_Z_INDEX);

        const canvasNode = this.node.parent;
        if (canvasNode) {
            canvasNode.addChild(modalNode);
        } else {
            this.node.addChild(modalNode);
        }
        this._timeoutModalNode = modalNode;

        const timeoutModal = modalNode.getComponent(TimeoutModal);
        if (timeoutModal) {
            timeoutModal.setParams({
                levelIndex: this._currentLevelNumber
            });
            timeoutModal.setCallbacks({
                onShare: () => {
                    console.log('[PageLevel] 超时弹窗分享完成');
                },
                onRestart: () => {
                    this._closeTimeoutModal();
                    this._enterAndInitLevel().catch(err => {
                        console.error('[PageLevel] 重新进入关卡失败:', err);
                    });
                },
                onHome: () => {
                    this._closeTimeoutModal();
                    if (this._isShareMode) {
                        ShareManager.instance.clearShareMode();
                        ViewManager.instance.replace('PageHome');
                    } else {
                        ViewManager.instance.back();
                    }
                }
            });
            timeoutModal.onViewLoad();
            timeoutModal.onViewShow();
        }

        console.log('[PageLevel] 显示超时弹窗');
    }

    /**
     * 关闭超时弹窗
     */
    private _closeTimeoutModal(): void {
        if (this._timeoutModalNode && this._timeoutModalNode.isValid) {
            this._timeoutModalNode.destroy();
            this._timeoutModalNode = null;
            console.log('[PageLevel] 关闭超时弹窗');
        }
    }

    /**
     * 显示错误提示
     */
    private showError(): void {
        console.log('[PageLevel] 答案错误！');

        // 播放失败音效
        this.playFailSound();

        // 触发手机震动
        WxSDK.vibrateLong();

        // 显示错误弹窗
        this._showWrongModal();
    }

    /**
     * 进入下一关
     * 正常模式：使用 complete 返回的 nextLevel 数据
     * 分享模式：按索引递增
     */
    private async goToNextLevel(): Promise<void> {
        if (this._isShareMode) {
            // 分享模式：按索引递增
            this._shareLevelIndex++;
            const totalLevels = ShareManager.instance.getShareLevelCount();
            if (this._shareLevelIndex >= totalLevels) {
                console.log('[PageLevel] 分享关卡全部完成');
                this.stopCountdown();
                ShareManager.instance.clearShareMode();
                ViewManager.instance.replace('PageHome');
                return;
            }
        } else {
            // 正常模式：使用 complete 返回的 nextLevel
            if (!this._nextLevelData) {
                // 没有下一关 → 全部通关
                console.log('[PageLevel] 恭喜通关！所有关卡已完成');
                this.stopCountdown();
                ViewManager.instance.back();
                return;
            }

            // 切换到下一关
            this._currentLevelId = this._nextLevelData.id;
            this._currentLevelNumber = this._nextLevelData.level;
            this._nextLevelData = null;
        }

        // 重置并加载下一关（包含进入关卡接口调用）
        await this._enterAndInitLevel();
        console.log(`[PageLevel] 进入关卡 第${this._currentLevelNumber}关`);
    }
}
