import { _decorator, Button, CachedArray, Component, instantiate, Node, Prefab, settings } from 'cc';
import { UIPanel } from '../base/UIPanel';
import { Level } from '../../components/level/Level';
import { LevelManager } from '../../Managers/global/data-flow/LevelManager';
import { LevelData } from '../../Managers/data/DataModel';
import { PopupType } from '../popup/PopupType';
import { ManagerType } from '../../Managers/global/data-flow/TopLevelManager';
import { GameManager } from '../../Managers/global/state/GameManager';
import { LevelPageNavigator } from '../../components/level/LevelPageNavigator';
import { LevelLabel } from '../../components/level/LevelLabel';
import { LevelPage } from '../../components/level/LevelPage';
import { Cards_Constants } from '../../constants/Cards_Constants';

const { ccclass, property } = _decorator;

/**
 * SUMMARY
 * -------
 * LevelPanel acts as a LevelPage's Manager 
 */

@ccclass('LevelCompDataClass')
export class LevelCompDataClass {
    public levelComps: Level[] = [];
    public labelComps: LevelLabel[] = [];

    constructor(levelCount) {
        this.levelComps = new Array(levelCount);
        this.labelComps = new Array(levelCount);
    }
}

@ccclass('LevelPanel')
export class LevelPanel extends UIPanel {
    @property({ type: LevelPageNavigator })
    public levelPageNavigator: LevelPageNavigator;

    @property({ type: Button })
    private playBtn: Button;

    @property({ type: Button })
    private backBtn: Button;

    @property({ type: Number })
    public maxLevelsAllowedInSinglePage: number = 4;

    private prevSelectedLevel: Level;
    private currentSelectedLevel: Level;
    private levelDatas: LevelData[];

    public lastSelectedLevel: number = 1;
    public lastUnlockedLevel: number = 1;

    private scrolledLevelPageIndex: number = -1;
    private totalLevelDataPages: number = 0;
    private allLevelPagesMap: Map<number, LevelData[]> = new Map<number, LevelData[]>();

    private hasSelectedLevel: boolean = false;

    private levelManager: LevelManager;
    private levelCompDataClass: LevelCompDataClass;
    private currentActiveLevelPage: LevelPage;

    private isLevelPageShown: boolean = false;

    public get CanSlideLeft(): boolean {
        return this.scrolledLevelPageIndex > 0;
    }

    public get CanSlideRight(): boolean {
        return this.scrolledLevelPageIndex < this.totalLevelDataPages - 1;
    }

    public get MaxLevelPagesForData(): number {
        return this.totalLevelDataPages;
    }

    public fn_HasSelectedLevel(): boolean {
        return this.hasSelectedLevel;
    }

    public get LevelManager(): LevelManager {
        return this.levelManager;
    }

    public fn_SetLastSelectedLevel(lvl: number) 
    {
        this.lastSelectedLevel = lvl;
    }

    protected onEnable(): void 
    {
        super.onEnable();

        this.playBtn.node.on(Button.EventType.CLICK, () => {
            this.fn_OnPlayButtonClicked();
            let gameManager = this.uiManager.MainManager.fn_GetMainManager(ManagerType.GAME) as GameManager;
            gameManager.fn_OnGameStart();
        });

        this.backBtn.node.on(Button.EventType.CLICK, () => {
            this.uiManager.fn_DeactivateCurrentActivePanel();
            this.uiManager.fn_ActivatePanel(PopupType.PT_MainMenu);
        });

        if (!this.isLevelPageShown) 
        {
            this.isLevelPageShown = true;
            setTimeout(() => 
            {
                this.ShowActiveLevelPage();
            }, Cards_Constants.MILLI_SEC * 0);
        }
        else 
        {
            this.ShowActiveLevelPage();
        }
    }

    private ShowActiveLevelPage() 
    {
        this.levelManager.fn_SlidePageToCurrentActivePage(false);

        if (!this.levelCompDataClass)
            this.levelCompDataClass = new LevelCompDataClass(this.currentActiveLevelPage.GetLevelComps.length);

        this.levelCompDataClass.levelComps = this.levelPageNavigator.currentMiddlePage.GetLevelComps;
        this.levelCompDataClass.labelComps = this.levelPageNavigator.currentMiddlePage.GetLevelLabelComps;

        console.log("### hasSelectedLevel: " + this.hasSelectedLevel);
        if (!this.hasSelectedLevel)
            this.fn_UpdateLastSelectedLevelUI();
    }

    private fn_UpdateLastSelectedLevelUI() 
    {
        console.log("### this.levelCompDataClass.levelComps: " + this.levelCompDataClass.levelComps[0].fn_GetLevelNum());
        console.log("### lastSelectedLvl: " + this.lastUnlockedLevel);
        console.log("### lastSelectedLevel: " + this.lastSelectedLevel);

        let lastSelectedLvlComp = this.levelCompDataClass.levelComps[this.fn_GetLevelIndexFromLastUnlockedLevel()];

        lastSelectedLvlComp.fn_ToggleSelection(true);
        lastSelectedLvlComp.fn_SetLevelLockState(true);
        this.fn_SetPrevAndCurrentLevelElements(lastSelectedLvlComp);
    }

    private fn_GetLevelIndexFromLastUnlockedLevel() 
    {
        let levelNumInPage = this.lastUnlockedLevel % this.maxLevelsAllowedInSinglePage;
        let level = levelNumInPage == 0 ? this.maxLevelsAllowedInSinglePage : levelNumInPage;

        return level - 1;
    }

    protected onDisable(): void {
        this.playBtn.node.off(Button.EventType.CLICK);
        this.backBtn.node.off(Button.EventType.CLICK);
    }

    public fn_InitLevelsData(levelDatas: LevelData[], selectedLvl: number, lastUnlockedLevel: number, levelManager: LevelManager) 
    {
        this.levelDatas = levelDatas;
        this.levelManager = levelManager;
        this.lastUnlockedLevel = lastUnlockedLevel;
        this.lastSelectedLevel = selectedLvl;

        // this.levelComps = new Array(this.maxLevelsInPage);

        // initializing the levels with the current pages levels
        this.levelPageNavigator.fn_Init(this);

        for (let i = 0; i < this.levelPageNavigator.fn_GetPagesCount; i++)
            this.levelPageNavigator.fn_IterateAndGetLevelPage(i).fn_Init();

        this.MapLevelDatas();
        this.fn_InitMiddlePage();
        this.fn_InitLevelUIData();
    }

    private fn_InitMiddlePage() 
    {
        this.scrolledLevelPageIndex++;

        this.currentActiveLevelPage = this.levelPageNavigator.currentMiddlePage;

        if (!this.levelCompDataClass)
            this.levelCompDataClass = new LevelCompDataClass(this.currentActiveLevelPage.GetLevelComps.length);

        this.levelCompDataClass.levelComps = this.currentActiveLevelPage.GetLevelComps;
        this.levelCompDataClass.labelComps = this.currentActiveLevelPage.GetLevelLabelComps;
    }

    public fn_UpdateNextPage() 
    {
        this.scrolledLevelPageIndex += 1;
        this.fn_GetAndInitCompsForNextPage();
        this.fn_InitLevelUIData();
    }

    public fn_UpdatePrevPage() 
    {
        this.scrolledLevelPageIndex -= 1;
        this.fn_GetAndInitCompsForNextPage();
        this.fn_InitLevelUIData();
    }

    private fn_GetAndInitCompsForNextPage() 
    {
        this.levelCompDataClass.levelComps = this.levelPageNavigator.nextPageToShow.GetLevelComps;
        this.levelCompDataClass.labelComps = this.levelPageNavigator.nextPageToShow.GetLevelLabelComps;
    }

    private fn_InitLevelUIData() 
    {
        console.log("## ScrolledPageIndex: " + this.scrolledLevelPageIndex);

        // let index = this.scrolledLevelPageIndex == this.allLevelPagesMap.size ? this.allLevelPagesMap.size - 1
        let levelDatas = this.allLevelPagesMap.get(this.scrolledLevelPageIndex);

        console.log("## ScrolledPageIndex LevelDatas first level: " + levelDatas[0].level);
        console.log("## ScrolledPageIndex LevelDatas.length: " + levelDatas.length);

        let levelsCounter = 0;
        for (let j = 0; j < this.maxLevelsAllowedInSinglePage; j++) 
        {
            this.levelCompDataClass.levelComps[j].fn_SetLevelData(levelDatas[j]);
            this.levelCompDataClass.levelComps[j].fn_Init(this, this.levelCompDataClass.labelComps[j]);
            if (levelDatas[j] != null)
                levelsCounter++;
        }

        this.levelPageNavigator.nextPageToShow.fn_SetLevelsCount(levelsCounter);
    }

    private MapLevelDatas() 
    {
        this.allLevelPagesMap = new Map<number, [LevelData]>();
        let maxLevelAvailableNow = this.levelDatas.length;
        let sliceStartIndex = 0;
        let sliceEndIndex = this.maxLevelsAllowedInSinglePage;
        let levelPageCounter = 0;

        while (maxLevelAvailableNow >= this.maxLevelsAllowedInSinglePage) // 50 >= 16 // 34 >= 16 // 18 >= 16
        {
            maxLevelAvailableNow -= this.maxLevelsAllowedInSinglePage; // 34 // 18 // 2

            // 34 >= 16 // 18 >= 16 // 2 >= 16

            this.allLevelPagesMap.set(levelPageCounter, this.levelDatas.slice(sliceStartIndex, sliceEndIndex)); // 0-15 // 16-31
            sliceStartIndex += this.maxLevelsAllowedInSinglePage; // 16 // 32 // 48
            sliceEndIndex += this.maxLevelsAllowedInSinglePage; // 32 // 48 // 64
            levelPageCounter++; // 1 // 2 // 3
        }

        let slicedArr = this.levelDatas.slice(sliceStartIndex, sliceStartIndex + maxLevelAvailableNow);
        
        console.log("init map: levelPageCounter: " + levelPageCounter);

        this.allLevelPagesMap.set(levelPageCounter, slicedArr);
        this.totalLevelDataPages = levelPageCounter + 1;

        console.log("Set LevelPageCounter: " + levelPageCounter);
        console.log("Set totalLevelDataPages: " + this.totalLevelDataPages);

        // this.allLevelPagesMap.get(3).forEach(data => console.log("data.level: " + data.level));
    }

    public fn_UpdateCurrentAndNewLevelElementsOnLevelComplete() 
    {
        console.log("fn_UpdateCurrentAndNewLevelElementsOnLevelComplete");

        if (this.prevSelectedLevel)
            console.log("### prevSelectedLevel: " + this.prevSelectedLevel.fn_GetLevelNum());

        console.log("### currentSelectedLevel: " + this.currentSelectedLevel.fn_GetLevelNum());

        this.prevSelectedLevel = this.currentSelectedLevel;
        this.currentSelectedLevel = this.levelCompDataClass.levelComps[this.prevSelectedLevel.fn_GetLevelNum() % this.maxLevelsAllowedInSinglePage];

        console.log("### prevSelectedLevel: " + this.prevSelectedLevel.fn_GetLevelNum());
        console.log("### currentSelectedLevel: " + this.currentSelectedLevel.fn_GetLevelNum());

        this.fn_SetLastUnlockedLevel(this.currentSelectedLevel.fn_GetLevelNum());
        console.log("GetLastUnlockedLevel: " + this.lastUnlockedLevel);

        if (this.prevSelectedLevel)
            this.prevSelectedLevel.fn_ToggleSelection(false);

        this.currentSelectedLevel.fn_ToggleSelection(true);
        this.currentSelectedLevel.fn_SetLevelLockState(true);

        this.levelManager.PassLevelData(
            this.currentSelectedLevel.fn_GetLevelNum(),
            this.currentSelectedLevel.fn_GetRow(),
            this.currentSelectedLevel.fn_GetCol());

        this.fn_UpdatePrevSelectedElement();
        this.fn_SetLevelSelectionState(true);
    }

    public fn_SetPrevAndCurrentLevelElements(newlySelectedLevel: Level) 
    {
        console.log("fn_SetPrevAndCurrentLevelElements");

        console.log("newlySelectedLevel.fn_GetLevelNum(): " + newlySelectedLevel.fn_GetLevelNum());
        if (this.currentSelectedLevel)
            console.log("newlySelectedLevel.fn_GetLevelNum(): " + this.currentSelectedLevel.fn_GetLevelNum());

        if (this.currentSelectedLevel != null && newlySelectedLevel.fn_GetLevelNum() == this.currentSelectedLevel.fn_GetLevelNum()) 
        {
            console.log("newlySelectedLevel.fn_GetLevelNum() == this.currentSelectedLevel.fn_GetLevelNum(): " + (newlySelectedLevel.fn_GetLevelNum() == this.currentSelectedLevel.fn_GetLevelNum()));
            return;
        }

        console.log("this.currentSelectedLevel: " + this.currentSelectedLevel);
        if (this.currentSelectedLevel)
            console.log("this.currentSelectedLevel: " + this.currentSelectedLevel.fn_GetLevelNum());

        this.prevSelectedLevel = this.currentSelectedLevel;
        // if (!this.prevSelectedLevel && onClick) // hotfix
        // {
        //     // console.log("#B lastSelectedLevel: " + this.lastSelectedLevel);
        //     // console.log("#B lastUnlockedLevel: " + this.lastUnlockedLevel);
        //     // console.log("#B this.fn_GetLevelIndexFromLastUnlockedLevel(): " + this.fn_GetLevelIndexFromLastUnlockedLevel());
        //     this.prevSelectedLevel = this.levelCompDataClass.levelComps[this.lastSelectedLevel - 1];
        // }

        this.currentSelectedLevel = newlySelectedLevel;

        if (this.prevSelectedLevel)
            console.log("### prevSelectedLevel: " + this.prevSelectedLevel.fn_GetLevelNum());
        console.log("### currentSelectedLevel: " + this.currentSelectedLevel.fn_GetLevelNum());

        this.levelManager.PassLevelData(this.currentSelectedLevel.fn_GetLevelNum(), this.currentSelectedLevel.fn_GetRow(), this.currentSelectedLevel.fn_GetCol());
        this.fn_UpdatePrevSelectedElement();
        this.fn_SetLevelSelectionState(true);

        console.log("this.lastSelectedLevel: " + this.lastSelectedLevel);
        console.log("this.lastUnlockedLevel: " + this.lastUnlockedLevel);
        this.levelManager.fn_UserDataBehaviour.fn_SetLevelUnlockedData(this.lastSelectedLevel, this.lastUnlockedLevel);
    }

    private fn_SetCurrentActivePage() {
        console.log("## this.levelPageNavigator.currentMiddlePage: " + this.levelPageNavigator.currentMiddlePage.node.name);
        console.log("## this.currentActiveLevelPage.GetLevelComps: " + this.currentActiveLevelPage.GetLevelComps[0].fn_GetLevelNum());
        console.log("## this.currentActiveLevelPage.GetLevelLabelComps: " + this.currentActiveLevelPage.GetLevelLabelComps[0]);

        this.currentActiveLevelPage = this.levelPageNavigator.currentMiddlePage;
        this.levelCompDataClass.levelComps = this.currentActiveLevelPage.GetLevelComps;
        this.levelCompDataClass.labelComps = this.currentActiveLevelPage.GetLevelLabelComps;
    }

    public fn_SetLevelSelectionState(state: boolean) 
    {
        this.hasSelectedLevel = state;
    }

    public fn_OnLevelRestart() 
    {
        this.prevSelectedLevel = this.currentSelectedLevel;
        let nextLevelNum = this.currentSelectedLevel.fn_GetLevelNum();
        nextLevelNum--;
        this.fn_UpdatePrevSelectedElement();
        this.currentSelectedLevel = this.levelCompDataClass.levelComps[nextLevelNum - 1]; // reusing the same completed level index
    }

    public fn_UpdatePrevSelectedElement() 
    {
        if (this.prevSelectedLevel) {
            console.log("Toggling selection: for prev: " + this.prevSelectedLevel.fn_GetLevelNum());
            this.prevSelectedLevel.fn_ToggleSelection(false);
        }

        if (this.prevSelectedLevel && this.currentSelectedLevel) {
            if (this.prevSelectedLevel.fn_GetLevelNum() == this.currentSelectedLevel.fn_GetLevelNum()) {
                this.prevSelectedLevel = this.currentSelectedLevel = null;
                console.log("Setting to NULL");
                this.fn_SetLevelSelectionState(false);
            }
        }
    }

    public fn_OnPlayButtonClicked() 
    {
        if (this.currentSelectedLevel != null) {
            this.uiManager.fn_DeactivateCurrentActivePanel();
        }
    }

    public fn_SetLastUnlockedLevel(newUnlockedLevel: number) 
    {
        console.log("## lastSelectedLevel: " + this.lastSelectedLevel);

        this.fn_SetLastSelectedLevel(newUnlockedLevel);

        if (!this.lastUnlockedLevel) {
            this.lastUnlockedLevel = newUnlockedLevel;
            this.fn_SetLastSelectedLevel(this.lastUnlockedLevel);

            console.log("## lastUnlockedLevel not set: " + this.lastUnlockedLevel);
            return;
        }

        if (newUnlockedLevel > this.lastUnlockedLevel)
        {
            console.log("## last has set here");
            this.lastUnlockedLevel = newUnlockedLevel;
        }
    } 
}

