import { _decorator, Component, EventTouch, instantiate, isValid, Node, Prefab, Sprite, UITransform, v3, Vec2, Vec3 } from 'cc'
import { ResMgr } from './ResMgr'
import { Bundle } from '../enum/Bundle'
import { Goods } from '../game/Goods'
import { EventMgr } from './EventMgr'
import { EventType } from '../enum/EventType'
import { ShelveLocker } from '../game/ShelveLocker'
import { ShelveBase } from '../scriptBase/ShelveBase'
import { Mode, ModeName } from '../enum/Mode'
import { StorageUtil } from '../util/StorageUtil'
import { ObjUtil } from '../util/ObjUtil'
import { AudioMgr } from './AudioMgr'
import { PREVIEW } from 'cc/env'
const { ccclass, property } = _decorator

const PickOffset: number = 80

@ccclass('Manager/GameMgr')
export class GameMgr extends Component {

    private static _inst: GameMgr = null
    private static _node: Node = null
    private static _uiTrans: UITransform = null

    public static get Stage(): Node {
        return this._node.children[0]
    }

    private static curLevel: object = {}
    public static get CurLevel(): number {
        if (!ObjUtil.has(this.curLevel, this.mode)) return 0
        return this.curLevel[this.mode]
    }

    public static get CurPassedLevel(): number {
        let passCnt: number = 0
        for (const mode in this.curLevel) {
            if (Object.prototype.hasOwnProperty.call(this.curLevel, mode)) {
                const level = this.curLevel[mode]
                passCnt += level
            }
        }
        return passCnt
    }


    public static get isHardLevel(): boolean {
        return (this.CurLevel + 1) % 5 === 0
    }

    private static unlockedMode: Mode[] = []
    public static mode: Mode = Mode.tp

    private static _pickedGoods: Goods = null
    private static _holdGoods: Node = null

    public static shelveArr: ShelveBase[] = []
    public static shelveLockerArr: ShelveLocker[] = []
    public static goodsArr: number[] = []
    public static goodsData = {}

    private static pause: boolean = false
    public static get Pause(): boolean {
        return this.pause
    }
    public static set Pause(v: boolean) {
        this.pause = v;
        EventMgr.emit(EventType.Pause, v)
    }

    protected onLoad(): void {
        globalThis.GameMgr = GameMgr
        GameMgr._inst = this
        GameMgr._node = this.node
        GameMgr._uiTrans = this.getComponent(UITransform)

        this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this)
        this.node.on(Node.EventType.TOUCH_END, this.onTouchFinish, this)
        this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchFinish, this)

        GameMgr.unlockedMode = StorageUtil.getObj('unlockedMode', [0])
        GameMgr.curLevel = StorageUtil.getObj('curLevel', { 0: 0 })
    }

    public static unlockMode(mode: Mode): void {
        if (this.unlockedMode.includes(mode)) return
        this.unlockedMode.push(mode)
        this.unlockedMode.sort()
        StorageUtil.setObj('unlockedMode', this.unlockedMode)
        EventMgr.emit(EventType.ModeUnlocked)
    }

    private static createStage(): void {
        const stagePre: Prefab = ResMgr.getRes(Bundle.Game, 'Stage')
        const stageNode: Node = instantiate(stagePre)
        this._node.addChild(stageNode)
    }

    public static startGame(): void {
        this.reset()
        this._node.destroyAllChildren()
        this._inst.scheduleOnce(() => {
            this.createStage()
        })
    }

    public static passGame(): void {
        if (!ObjUtil.has(this.curLevel, this.mode)) {
            this.curLevel[this.mode] = 0
        }
        this.curLevel[this.mode]++
        StorageUtil.setObj('curLevel', this.curLevel)
        if (this.mode === Mode.tp && this.curLevel[this.mode] >= 15) {
            this.unlockMode(Mode.gs)
        } else if (this.mode === Mode.gs && this.curLevel[this.mode] >= 10) {
            this.unlockMode(Mode.ls)
        }
    }

    public static quitGame(): void {
        this._node.destroyAllChildren()
        this.reset()
    }

    public static pick(goods: Goods, uiPos: Vec2): void {
        this._pickedGoods = goods
        this._holdGoods = new Node()
        const sp: Sprite = this._holdGoods.addComponent(Sprite)
        sp.spriteFrame = goods.Sp.spriteFrame
        this._node.addChild(this._holdGoods)
        uiPos.y += PickOffset
        const localPos: Vec3 = GameMgr._uiTrans.convertToNodeSpaceAR(v3(uiPos.x, uiPos.y, 0))
        this._holdGoods.setPosition(localPos)
        AudioMgr.playSfx('点击消除物')
    }

    public static release(): void {
        let isSuccess: boolean = false
        const holdGoodsWorldPos: Vec3 = this._holdGoods.getWorldPosition()
        for (let i = 0; i < this.shelveArr.length; i++) {
            const shelve: ShelveBase = this.shelveArr[i]
            if (shelve.getComponentInChildren(ShelveLocker)) continue
            const uiTrans: UITransform = shelve.getComponent(UITransform)
            const shelveWorldPos: Vec3 = shelve.node.getWorldPosition()
            const goodsLocalPos: Vec3 = uiTrans.convertToNodeSpaceAR(holdGoodsWorldPos)
            const disX: number = Math.abs(shelveWorldPos.x - holdGoodsWorldPos.x)
            const disY: number = Math.abs(shelveWorldPos.y - holdGoodsWorldPos.y)
            if (disX < uiTrans.width / 2 && disY < uiTrans.height / 2) {
                const slotId: number = shelve.getSlot(goodsLocalPos)
                if (slotId < 0 || shelve.isSlotOccupied(slotId)) break
                const goodsId: number = this._pickedGoods.Id
                shelve.placeGoods(goodsId, slotId)
                isSuccess = true
                break
            }
        }
        if (isSuccess) {
            EventMgr.emit(EventType.PlaceGoods)
        } else {
            this._pickedGoods.Visible = true
        }
        this._pickedGoods = null
        this._holdGoods.destroy()
        this._holdGoods = null
        AudioMgr.playSfx('放下消除物')
    }

    public static get isPicking(): boolean {
        return !!this._pickedGoods
    }

    private onTouchMove(e: EventTouch): void {
        const holdGoods: Node = GameMgr._holdGoods
        if (!isValid(holdGoods)) return
        const uiPos: Vec2 = e.getUILocation()
        uiPos.y += PickOffset
        const localPos: Vec3 = GameMgr._uiTrans.convertToNodeSpaceAR(v3(uiPos.x, uiPos.y, 0))
        holdGoods.setPosition(localPos)

    }

    private onTouchFinish(e: EventTouch): void {
        if (!isValid(GameMgr._holdGoods)) return
        GameMgr.release()
    }

    private static reset(): void {
        this._pickedGoods = null
        this._holdGoods = null
        this.shelveArr = []
        this.shelveLockerArr = []
        this.goodsArr = []
        this.goodsData = {}
    }

    public static isModeUnlocked(mode: Mode): boolean {
        return this.unlockedMode.includes(mode)
    }

    public static get isModeAllUnlocked(): boolean {
        return this.unlockedMode.length >= ModeName.length
    }

    public static get isStucked(): boolean {
        for (let i = 0; i < this.shelveArr.length; i++) {
            const shelve: ShelveBase = this.shelveArr[i];
            if (!shelve.isAllSlotOccupied()) return false
        }
        return true
    }
}

if (PREVIEW) {
    globalThis.GameMgr = GameMgr
}

