import { GameConfig } from "../../config/GameConfig";
import { IGameModelElement } from "../../config/GameModel";
import { TraceUtil } from "../../modules/analyticModule/TraceUtil";
import { UITips } from "../../modules/game1/bossModule/UITips";
import CgModuleC from "../../modules/game2/cgModules/CgModuleC";
import { MatchModuleC } from "../../modules/matchModule/MatchModuleC";
import PlayerData from "../../modules/playerModule/PlayerData";
import LevelItem_Generate from "../../ui-generate/level/LevelItem_generate";
import LevelPanel_Generate from "../../ui-generate/level/LevelPanel_generate";

/** levelPanel 下 contentCanvas的 槽 */
class UISlot {

    /** z系数 */
    zOrder: number = 0;

    /** 缩放 */
    scale: Vector2 = new Vector2(0, 0);

    pos: Vector2 = new Vector2(0, 0);

    constructor(zOrder: number, scale: Vector2, pos: Vector2) {
        this.zOrder = zOrder;
        this.scale = scale;
        this.pos = pos;
    }
}

/** 5个自定义槽 - 实际上放7个 - 避免留白的问题 */
class FiveSlot {

    slotList: UISlot[] = [];

    constructor() {
        // TODO: 搞6个，一个模式两个
        // this.slotList.push(new UISlot(1, new Vector2(1, 0.86), new Vector2(-470, 0)));
        this.slotList.push(new UISlot(1, new Vector2(1, 0.86), new Vector2(-170, 0)));
        this.slotList.push(new UISlot(2, new Vector2(1, 0.93), new Vector2(130, 0)));
        this.slotList.push(new UISlot(3, new Vector2(1, 1.00), new Vector2(430, 0)));
        this.slotList.push(new UISlot(2, new Vector2(1, 0.93), new Vector2(730, 0)));
        this.slotList.push(new UISlot(1, new Vector2(1, 0.86), new Vector2(1030, 0)));
        this.slotList.push(new UISlot(1, new Vector2(1, 0.86), new Vector2(1330, 0)));
    }
}

/** 帧 */
const INTER_STAMP: number = 100;

/** 惯性帧 */
const INTER_STAMP2: number = 8;

/** 几秒停止惯性 */
const STOP_INERTIA: number = 3;

/** 惯性系数 */
const INERTIA_COE: number = 5;

/** 最小惯性速度 */
const MIN_INERTIA_VELOCITY: number = 5;

/** 最中间那个 */
const MIDDLE_ID: number = 2;

/** 中间位置印射在每一个UI SLOT区间的缩放系数 */
const SCALE_RATIO: number = 0.07 / 165;

/** 进度条值系数 */
const PRO_BAR_RATIO: number = 1290 / 1000;

/** 吸附距离判定 */
const ATTACH_DIS: number = 100;

/** 被算作点击的时间戳 */
const CLICK_TIME: number = 200;

export default class LevelPanel extends LevelPanel_Generate {

    protected slotInstance: FiveSlot = new FiveSlot();

    protected levelItemList: LevelItem[] = [];

    /** 上一帧滚动条 */
    protected lastStampProBarValue: number = 0;

    /** 按钮滚动条后才有 onSliderChange的回调 */
    protected isPressed: boolean = false;

    /** 上一个inter帧的进度条的value */
    protected lastInterProBarValue: number = 0;

    /** 当前inter帧的进度条的value */
    protected curInterProBarValue: number = 0;

    /** 计时器 */
    protected inter: any = null;

    /** 计时器时间戳 */
    protected timerStamp: number = 0;

    /** 惯性滑动的计时器 */
    protected inter2: any = null;

    /** onRelease是否锁定 */
    protected isReleaseLocked: boolean = false;

    /** 按下时间戳 */
    protected pressTimeStamp: number = 0;

    protected modeList: IGameModelElement[] = [];

    private initSlot() {

        // 过滤出可选的模式
        GameConfig.GameModel.getAllElement().forEach((gameModeCfg) => {
            if (gameModeCfg.icon) { this.modeList.push(gameModeCfg); }
        });

        this.slotInstance.slotList.forEach((slot: UISlot, index: number) => {
            const levelItem = UI.UIManager.instance.create(LevelItem);
            this.levelItemList.push(levelItem);
            this.contentCanvas.addChild(levelItem.uiObject);
            levelItem.initSlot(index, this.slotInstance.slotList);
            levelItem.bindCfg(this.modeList[index % this.modeList.length]);
            levelItem.uiObject.position = slot.pos;
            levelItem.uiObject.renderScale = slot.scale;
            levelItem.uiObject.zOrder = slot.zOrder;
        });

        this.startGameBtn.onClicked.add(this.matchGame.bind(this));
    }

    protected override onShow(...params: any[]): void {
        this.enableClassicMode();

    }

    /** 默认启用经典模式 */
    private enableClassicMode() {
        // 第一个模式是经典模式，过滤拿到它的列表
        const firstLevelItemList = this.levelItemList.filter(item => { return item.gameModeCfg === this.modeList[0]; });
        // 最小距离
        let minStep = Number.MAX_VALUE;
        firstLevelItemList.forEach(item => { minStep = Math.abs(minStep) > Math.abs(item.getToMiddleSlotDis()) ? item.getToMiddleSlotDis() : minStep; })
        this.move(minStep);
    }

    /** 匹配游戏模式 */
    private matchGame() {
        UI.UIManager.instance.hideUI(this);
        for (const item of this.levelItemList) {
            if (item.isBeSelect()) {
                if (!item.checkIsUnlock()) {
                    TraceUtil.buttonClick("2sgopen");
                    UITips.show(GameConfig.LanguageConfig.UITipsMode_14.value);
                    return;
                }
                ModuleManager.getInstance().getModule(CgModuleC).reqCreateGame(item.gameModeCfg.id)
                // switch (item.gameModeCfg.type) {
                //     // 经典模式
                //     case 2:
                //     // 冰雪模式
                //     case 3:
                //         ModuleManager.getInstance().getModule(CgModuleC).waitingStart(item.gameModeCfg.id);
                //         break;
                //     case 5:
                //         ModuleManager.getInstance().getModule(CgModuleC).reqCreateGame(item.gameModeCfg.id)
                //         break;
                //     default:
                //         ModuleManager.getInstance().getModule(CgModuleC).waitingStart(item.gameModeCfg.id);
                // }
                return;
            }
        }
    }

    protected onAwake() {
        this.initButtons();
        this.initSlot();
        this.proBar.sliderButtonPressDelegate.add(this.onPress.bind(this));
        this.proBar.sliderButtonReleaseDelegate.add(this.onRelease.bind(this));
        this.proBar.onSliderValueChanged.add(this.onChange.bind(this));
        this.leftBtn.onClicked.add(() => {
            this.move(-1);
            TraceUtil.buttonClick("2sgup");
        });
        this.rightBtn.onClicked.add(() => {
            this.move(1);
            TraceUtil.buttonClick("2sgdn");
        });
        this.mBtnQuit.onClicked.add(() => {
            TraceUtil.buttonClick("2exit");
            UI.UIManager.instance.hideUI(this);
        })
    }

    /**
     * 移动多少格子
     * @param step 步长 矢量 如1代表右移一格，-1代表左移一格
     */
    public move(step: number) {
        // 移动0格没有意义
        if (step === 0) { return; }
        let isRight = step > 0;
        let moveCount = Math.abs(step);
        let absOffset = this.slotInstance.slotList[MIDDLE_ID + moveCount].pos.x - this.slotInstance.slotList[MIDDLE_ID].pos.x;
        let offset = isRight ? absOffset : -absOffset;
        let velocity = offset / moveCount / INTER_STAMP2;
        let absVelocity = Math.abs(velocity);
        this.shiftItem(absOffset, absVelocity, velocity);
    }

    private shiftItem(absOffset: number, absVelocity: number, velocity: number) {
        this.levelItemList.forEach((levelItem) => { levelItem.startUpdate() });
        if (this.inter2) {
            clearInterval(this.inter2);
            this.inter2 = null
        }

        // 绝对速度这个值，那还是别动了
        if (absVelocity < MIN_INERTIA_VELOCITY) { this.levelItemList.forEach(item => { item.endUpdate(); }); return; }

        this.inter2 = setInterval(() => {
            this.levelItemList.forEach((levelItem) => { levelItem.uiObject.position = new Vector2(levelItem.uiObject.position.x + velocity, 0); })
            if (absOffset <= 0) {
                clearInterval(this.inter2);
                this.inter2 = null;
                // 关闭update
                this.levelItemList.forEach(item => { item.endUpdate(); });
            }
            absOffset -= absVelocity;
        }, INTER_STAMP2);
    }

    /** 进度条释放的回调 */
    private onRelease(value: number) {
        // TODO: 024 bug，点击进度条马上就有onRelease回调，这里加个锁简单处理一下
        if (this.isReleaseLocked) { return; }

        // // 如果和按下时间戳相差不超过500ms，那么就是点击事件
        // if (Date.now() - this.pressTimeStamp < CLICK_TIME) { this.onClicked(value); return; }

        //惯性
        this.isPressed = false;
        // 计算当前时间戳
        let now = Date.now();
        // 计算惯性的值，默认是上一帧进度条的值，如果当前时间和上一帧的时间戳间隔小于计时器间隔那么取 上一帧的进度条值，否则取当前帧的进度条值
        let interValue = now - this.timerStamp < INTER_STAMP ? this.lastInterProBarValue : this.curInterProBarValue;
        // 惯性滑动距离 * 惯性系数
        let offset = (value - interValue) * INERTIA_COE;
        // 偏移量的绝对值
        let absOffset = Math.abs(offset);
        // 惯性滑动速度 - 带方向的
        let velocity = offset / STOP_INERTIA / INTER_STAMP2;
        // 绝对速度 - 无方向
        let absVelocity = Math.abs(velocity);
        this.shiftItem(absOffset, absVelocity, velocity);
    }

    // TODO: 计算得不太准确,保留滚动就行了
    // onClicked(value: number) {
    // 精确的点击X位置
    // const precisePosX = value * PRO_BAR_RATIO;
    // for (const levelItem of this.levelItemList) {
    //     if (levelItem.checkBeClicked(precisePosX)) { break; }
    // }
    // }

    /** 进度条按钮的回调 */
    private onPress(value: number) {
        // TODO: 024 bug，点击进度条马上就有onRelease回调，这里加个锁简单处理一下
        this.isReleaseLocked = true;
        setTimeout(() => {
            this.isReleaseLocked = false;
        }, INTER_STAMP2 * 10);

        // // 记录按下的时间戳
        // this.pressTimeStamp = Date.now();
        // 开启update
        this.levelItemList.forEach(item => { item.startUpdate(); });

        //记录拖动起始帧滚动条value值
        this.lastStampProBarValue = value;
        this.isPressed = true;

        /** 双指针取每帧进度条的值 */
        this.lastInterProBarValue = value;
        this.curInterProBarValue = value;

        // 还有惯性就清掉了
        if (this.inter2) {
            clearInterval(this.inter2);
            this.inter2 = null;
            this.levelItemList.forEach(item => { item.endUpdate(); });
        }

        this.timerStamp = null;
        if (this.inter) clearInterval(this.inter);
        this.inter = setInterval(() => {
            if (this.timerStamp != null) this.lastInterProBarValue = this.curInterProBarValue;
            this.curInterProBarValue = this.proBar.currentValue;
            this.timerStamp = Date.now();
        }, INTER_STAMP);
    }

    /** 进度条改变的回调 */
    private onChange(value: number) {
        // 避免先触发改变值的回调
        if (!this.isPressed) return;
        // // 避免影响模拟的onclick事件触发
        // if (Date.now() - this.pressTimeStamp < CLICK_TIME) { return; }
        //对比上一帧滚动条value比较值计算所有LevelItem的偏移值
        let offset = (value - this.lastStampProBarValue) * PRO_BAR_RATIO;
        // 偏差值大于0是向右滑动，小于0是向左滑动
        this.levelItemList.forEach((levelItem) => {
            levelItem.uiObject.position = new Vector2(levelItem.uiObject.position.x + offset, 0);
        })
        this.lastStampProBarValue = value;
    }

    /** 获取所有levelItem */
    public reqAllLevelItem() {
        return this.levelItemList;
    }

    protected onHide() {
        clearInterval(this.inter);
        this.inter = null;
        this.levelItemList.forEach(item => { item.endUpdate(); });
    }
}

// const imageGuidList: string[] = ["120359", "133106", "133104", "120359", "133106", "133104", "120359", "133106", "133104"];

class LevelItem extends LevelItem_Generate {

    /** 所有的槽 */
    protected slotList: UISlot[] = [];

    /** 上一个槽ID */
    protected lastSlotID: number = 0;

    /** 当前槽ID */
    protected curSlotID: number = 0;

    /** 下一个槽ID */
    protected nextSlotID: number = 0;

    private _levelPanel: LevelPanel;

    /** 是否被选中 */
    public isBeSelect(): boolean {
        return this.curSlotID === MIDDLE_ID;
    }

    private _playerData: PlayerData;

    /** 离中间格子的距离，返回距离多少格子，有方向 */
    public getToMiddleSlotDis(): number {
        return MIDDLE_ID - this.curSlotID;
    }

    public get playerData(): PlayerData {
        if (!this._playerData) { this._playerData = DataCenterC.getInstance().getData(PlayerData); }
        return this._playerData;
    }

    public checkIsUnlock(): boolean {
        return this.playerData.isUnlock(this.gameModeCfg.id);
    }

    protected get levelPanel() {
        if (!this._levelPanel) {
            this._levelPanel = UI.UIManager.instance.getUI(LevelPanel);
        }
        return this._levelPanel;
    }

    public gameModeCfg: IGameModelElement;

    bindCfg(cfg: IGameModelElement) {
        this.gameModeCfg = cfg;
        this.descTxt.text = cfg.desc;
        this.bgImg.imageGuid = cfg.icon;
        this.modeNameTxt.text = cfg.name;
        if (this.checkIsUnlock()) {
            this.lockImg.visibility = UI.SlateVisibility.Collapsed;
        } else {
            switch (this.gameModeCfg.type) {
                // 冰雪模式
                case 3:
                    let gameTime = DataCenterC.getInstance().getData(PlayerData).getGameTimes(1203);
                    this.descTxt.text = StringUtil.format(GameConfig.LanguageConfig.UITipsMode_02.value, gameTime);
                    break;
                // // 熔岩模式
                // case 5: this.descTxt.text = GameConfig.LanguageConfig.UITipsMode_15.value; break;
                // 无尽模式
                case 5:
                    this.descTxt.text = GameConfig.LanguageConfig.UITipsMode_15.value;
                    break;
                default: this.descTxt.text = cfg.desc
            }
            this.lockImg.visibility = UI.SlateVisibility.SelfHitTestInvisible;
            this.playerData.onUnlockChange.add(this.watchUnlock.bind(this));
        }
    }

    /** 监听是否解锁 */
    private watchUnlock(unlockID: number) {
        if (this.gameModeCfg.id === unlockID) {
            this.descTxt.text = this.gameModeCfg.desc;
            this.lockImg.visibility = UI.SlateVisibility.Collapsed;
            this.playerData.onUnlockChange.remove(this.watchUnlock, this);
        }
    }

    /** 初始化绑定槽 */
    public initSlot(index: number, slotList: UISlot[]) {
        this.slotList = slotList;
        this.curSlotID = index;
        this.bindSlot();
        // TODO: 因为按钮被进度条挡住，点击事件没法穿透点击到这个，现在使用进度条的点击位置来计算所点击的item
        this.itemBtn.onClicked.add(this.shiftToMiddleLoc.bind(this));
    }

    /**
     * 检测这个item是不是被点击到了
     * @param 精确的点击X位置
     */
    public checkBeClicked(precisePosX: number): boolean {
        if (precisePosX < this.slotList[this.nextSlotID].pos.x && precisePosX > this.slotList[this.curSlotID].pos.x) {
            this.shiftToMiddleLoc();
            return true;
        } else {
            return false;
        }
    }

    /** 滑向最中间的位置 */
    public shiftToMiddleLoc() {
        // 当前已在最中间位置就不执行
        if (this.curSlotID === MIDDLE_ID) return;
        // 实际就是计算当前在最中间位置的item应该左移或右移几个位置
        this.levelPanel.move(this.curSlotID - MIDDLE_ID);
    }

    /** 绑定槽 */
    protected bindSlot() {
        if (this.curSlotID === MIDDLE_ID) { this.mImgSelect.visibility = UI.SlateVisibility.SelfHitTestInvisible; }
        this.lastSlotID = this.curSlotID > 0 ? this.curSlotID - 1 : this.slotList.length - 1;
        this.nextSlotID = this.curSlotID < this.slotList.length - 1 ? this.curSlotID + 1 : 0;
    }

    /**
     * 重新绑定槽
     * @param isNext 是否是下一个
     */
    private reBindSlot(isNext: boolean) {
        this.mImgSelect.visibility = UI.SlateVisibility.Collapsed;
        if (isNext) {
            this.curSlotID = this.nextSlotID;
        } else {
            this.curSlotID = this.lastSlotID;
        }
        this.bindSlot();
        this.applySlotInfo();
    }

    /** 启用更新 */
    public startUpdate() {
        this.canUpdate = true;
    }

    /** 结束更新，并强制回归到槽的信息设定 */
    public endUpdate() {
        this.canUpdate = false;
        // 没有吸附就重新应用槽的信息
        !this.attach() && this.applySlotInfo();
    }

    /** 是否是中间那个 */
    get isMiddleID(): boolean {
        return this.curSlotID === MIDDLE_ID;
    }

    /** 吸附 */
    private attach(): boolean {
        if (this.curSlotID != MIDDLE_ID) return;
        // 结束判断中间节点的位置，看是否需要吸附处理
        if (Math.abs(this.uiObject.position.x - this.slotList[this.nextSlotID].pos.x) <= ATTACH_DIS) {
            this.levelPanel.reqAllLevelItem().forEach((item) => { item.reBindSlot(true); });
            return true;
        }
        if (Math.abs(this.uiObject.position.x - this.slotList[this.lastSlotID].pos.x) <= ATTACH_DIS) {
            this.levelPanel.reqAllLevelItem().forEach((item) => { item.reBindSlot(false); });
            return true;
        }
        return false;
    }

    /**
    * 每一帧调用
    * 通过canUpdate可以开启关闭调用
    * dt 两帧调用的时间差，毫秒
    */
    protected onUpdate(dt: number) {
        // 中间的去影响所有的
        if (!this.isMiddleID) return;

        /** 缩放检测 */
        this.checkScaleChange();

        /** 右滑 */
        if (this.uiObject.position.x > this.slotList[this.curSlotID].pos.x) {
            this.checkScrollToRight();
        }

        /** 左滑 */
        if (this.uiObject.position.x < this.slotList[this.curSlotID].pos.x) {
            this.checkScrollToLeft();
        }
    }

    /** 缩放检测 */
    private checkScaleChange() {
        const twoSlotDis = this.uiObject.position.x - this.slotList[this.curSlotID].pos.x;
        const toScaleY = twoSlotDis * SCALE_RATIO;
        this.levelPanel.reqAllLevelItem().forEach((item) => { item.updateScale(toScaleY); });
    }

    /** 右滑检测 */
    private checkScrollToRight() {
        if (this.uiObject.position.x >= this.slotList[this.nextSlotID].pos.x) {
            this.levelPanel.reqAllLevelItem().forEach((item) => { item.reBindSlot(true); });
        }
    }

    /** 左滑检测 */
    private checkScrollToLeft() {
        if (this.uiObject.position.x <= this.slotList[this.lastSlotID].pos.x) {
            this.levelPanel.reqAllLevelItem().forEach((item) => { item.reBindSlot(false); });
        }
    }

    /** 应用槽信息 */
    private applySlotInfo() {
        this.uiObject.zOrder = this.slotList[this.curSlotID].zOrder;
        this.uiObject.position = this.slotList[this.curSlotID].pos;
        this.uiObject.renderScale = this.slotList[this.curSlotID].scale;
    }

    /**
     * 动态改变每个item的缩放
     * @param toScaleY toScaleY是一个矢量，正负表示方向
     */
    public updateScale(toScaleY: number) {
        if (this.curSlotID < MIDDLE_ID) {
            this.uiObject.renderScale = new Vector2(1, this.slotList[this.curSlotID].scale.y + toScaleY);
            this.checkOverScale(toScaleY >= 0, true);
        } else if (this.curSlotID > MIDDLE_ID) {
            this.uiObject.renderScale = new Vector2(1, this.slotList[this.curSlotID].scale.y - toScaleY);
            this.checkOverScale(toScaleY <= 0, false);
        } else {
            // 在中间的一定是减
            this.uiObject.renderScale = new Vector2(1, this.slotList[this.curSlotID].scale.y - Math.abs(toScaleY));
            // 这儿last 还是 next都可以
            this.checkOverScale(false);
        }
    }

    /**
     * 检查改变的scale是否超过了将要变成的scale
     * @param isAddScale scale是否增长
     * @param isLeft 是否是左边的 default true
     */
    private checkOverScale(isAddScale: boolean, isLeft: boolean = true) {
        if (isAddScale) {
            let slotID = isLeft ? this.nextSlotID : this.lastSlotID;
            const nextScaleY = this.slotList[slotID].scale.y;
            if (this.uiObject.renderScale.y >= nextScaleY) { this.uiObject.renderScale = this.slotList[slotID].scale; }
        } else {
            let slotID = isLeft ? this.lastSlotID : this.nextSlotID;
            const lastScaleY = this.slotList[slotID].scale.y;
            if (this.uiObject.renderScale.y <= lastScaleY) { this.uiObject.renderScale = this.slotList[slotID].scale; }
        }
    }
}
