import * as PIXI from "../pixi/pixi.mjs";
import { loadGameAssets } from "./AssetsLoader/AssetsLoader";
import { UICameraInfo, UIGameProfilerPipe, UIMainPipe, UIObtainedResourcesPipe, UISelectionInfo } from "./UIPipes/UIPipes";
import { getSpriteFromAtlas } from "./Utils/Sprites.utils";
import { profileFPS } from "./Profiler/Profiler";
import { createKeyboardBinding, inputControllerTick } from "./InputController/InputController";
import { BC_APP, BC_BUILDING_PLACEHOLDERS, BC_CAMERA, BC_SPRITES_SETTINGS, BC_VIEWPORT, BC_WORLD, PRNG, setBC_APP, setBC_SELECTION, setBC_VIEWPORT, setBC_WORLD } from "./GlobalVariables/GlobalVariables";
import { clampNumber, interpolate,  } from "./Utils/Math.utils";
import { calculateViewportFromCamera, moveHorizontally, moveVertically, screenToWorldCoordinates } from "./Camera/Camera";

import {
    addToBuildings,
    createFirstWorldChunks,
    getChunk,
    getObjectFromBuildingsLayer,
    getObjectFromTerrainLayer,
    getObjectFromVegetationLayer,
    removeFromVegetation,
    updateChunksVisibility,
    worldCoordinatesToChunkIndexesCoordinates,
    worldCoordinatesToChunkLocalCoordinates,
} from "./WorldGeneration/WorldGeneration";
import { handleBuildingsIncome, incBuildingCount } from "./Buildings/Buildings";
import { handleDayNightCycle } from "./World/DayNightCycle";
import { ambientDay, ambientMusic, ambientNight, handleSounds } from "./Sound/Sound";
import { handleChunkFilling } from "./WorldGeneration/ChunkFillQueue";

export function generateWorld() {

    createFirstWorldChunks();
    startGame();
}

function setupGlobalInput() {
    window.addEventListener("wheel", (event) => {
        const delta = Math.sign(event.deltaY);
        if (delta > 0) {
            BC_CAMERA.targetZoom = Number(clampNumber(BC_CAMERA.targetZoom - BC_CAMERA.zoomStep, BC_CAMERA.minZoom, BC_CAMERA.maxZoom).toFixed(2));
        } else {
            BC_CAMERA.targetZoom = Number(clampNumber(BC_CAMERA.targetZoom + BC_CAMERA.zoomStep, BC_CAMERA.minZoom, BC_CAMERA.maxZoom).toFixed(2));
        }
        UICameraInfo.update((s) => {
            s.zoom = BC_CAMERA.targetZoom;
        });
    });
}

function setupInGameSelector() {

    let ph = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(0, 0, 16, 16));
    ph.scale.set(BC_SPRITES_SETTINGS.scale);
    ph.alpha = 0.5;
    ph.visible = false;
    ph.zIndex = 1;
    BC_BUILDING_PLACEHOLDERS.push(ph);
    BC_VIEWPORT.addChild(ph);
    ph = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 0, 16, 16));
    ph.scale.set(BC_SPRITES_SETTINGS.scale);
    ph.alpha = 0.5;
    ph.visible = false;
    ph.zIndex = 1;
    BC_BUILDING_PLACEHOLDERS.push(ph);
    BC_VIEWPORT.addChild(ph);
    ph = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(0, 16, 16, 16));
    ph.scale.set(BC_SPRITES_SETTINGS.scale);
    ph.alpha = 0.5;
    ph.visible = false;
    ph.zIndex = 1;
    BC_BUILDING_PLACEHOLDERS.push(ph);
    BC_VIEWPORT.addChild(ph);
    ph = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 16, 16, 16));
    ph.scale.set(BC_SPRITES_SETTINGS.scale);
    ph.alpha = 0.5;
    ph.visible = false;
    ph.zIndex = 1;
    BC_BUILDING_PLACEHOLDERS.push(ph);
    BC_VIEWPORT.addChild(ph);
    ph = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(0, 32, 16, 16));
    ph.scale.set(BC_SPRITES_SETTINGS.scale);
    ph.alpha = 0.5;
    ph.visible = false;
    ph.zIndex = 1;
    BC_BUILDING_PLACEHOLDERS.push(ph);
    BC_VIEWPORT.addChild(ph);
    ph = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 32, 16, 16));
    ph.scale.set(BC_SPRITES_SETTINGS.scale);
    ph.alpha = 0.5;
    ph.visible = false;
    ph.zIndex = 1;
    BC_BUILDING_PLACEHOLDERS.push(ph);
    BC_VIEWPORT.addChild(ph);

    UIMainPipe.subscribe((s)=>{
        for (const i of BC_BUILDING_PLACEHOLDERS) {
            i.visible = false;
        }
        BC_BUILDING_PLACEHOLDERS[s.selectedBuilding].visible = true;
    });

    let sprite0 = PIXI.Sprite.from("assets/images/selection.png");
    sprite0.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale);
    BC_VIEWPORT.addChild(sprite0);
    sprite0.zIndex = 100;
    setBC_SELECTION(sprite0);

    BC_VIEWPORT.eventMode = "static";
    BC_VIEWPORT.onmousemove = (e) => {
        let t = screenToWorldCoordinates(e.data.global.x, e.data.global.y);
        let terrainObject = getObjectFromTerrainLayer(t.x, t.y);
        let vegetationObject = getObjectFromVegetationLayer(t.x, t.y);
        let buildingObject = getObjectFromBuildingsLayer(t.x, t.y);

        UISelectionInfo.update((s) => {
            let t_arr = [];
            if (terrainObject) {
                t_arr.push(terrainObject.type);
            }
            if (vegetationObject) {
                t_arr.push(vegetationObject.type);
            }
            s.types = [...t_arr];
        });

        t.x = BC_SPRITES_SETTINGS.defaultSize * BC_SPRITES_SETTINGS.scale * Math.floor(t.x / (BC_SPRITES_SETTINGS.defaultSize * BC_SPRITES_SETTINGS.scale));
        t.y = BC_SPRITES_SETTINGS.defaultSize * BC_SPRITES_SETTINGS.scale * Math.floor(t.y / (BC_SPRITES_SETTINGS.defaultSize * BC_SPRITES_SETTINGS.scale));
        sprite0.position.set(t.x, t.y);

        if(UIMainPipe.get().building && terrainObject.type !== "ter_water" && !vegetationObject && !buildingObject)
        {
            let q = UIMainPipe.get().selectedBuilding;
            BC_BUILDING_PLACEHOLDERS[q].visible = true;
            BC_BUILDING_PLACEHOLDERS[q].position.set(t.x, t.y);
        }
        else
        {
            BC_BUILDING_PLACEHOLDERS[UIMainPipe.get().selectedBuilding].visible = false;
        }
    };

    BC_VIEWPORT.onpointerdown = (e)=>{
        let t = screenToWorldCoordinates(e.data.global.x, e.data.global.y);
        let terrainObject = getObjectFromTerrainLayer(t.x, t.y);
        let vegetationObject = getObjectFromVegetationLayer(t.x, t.y);
        let buildingObject = getObjectFromBuildingsLayer(t.x, t.y);
        // console.log(vegetationObject);
        if(UIMainPipe.get().building && terrainObject.type !== "ter_water" && !vegetationObject && !buildingObject)
        {
            if(UIObtainedResourcesPipe.get().gold >= 50)
            {
                let chunk = getChunk(t.x, t.y);
                if(chunk)
                {
                    let ns;
                    switch(UIMainPipe.get().selectedBuilding)
                    {
                        case 0:
                            ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(0, 0, 16, 16));
                            break;
                        case 1:
                            ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 0, 16, 16));
                            break;
                        case 2:
                            ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(0, 16, 16, 16));
                            break;
                        case 3:
                            ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 16, 16, 16));
                            break;
                        case 4:
                            ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(0, 32, 16, 16));
                            break;
                        case 5:
                            ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 32, 16, 16));
                            break;
                    }
                    ns.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale);
                    let r = worldCoordinatesToChunkIndexesCoordinates(t.x, t.y);
                    // console.log(r);
                    addToBuildings(chunk, ns, {type: "building"}, r.x, r.y);
                    r = worldCoordinatesToChunkLocalCoordinates(t.x, t.y);
                    // console.log(r);
                    ns.position.set(r.x * BC_SPRITES_SETTINGS.scale * BC_SPRITES_SETTINGS.defaultSize, r.y * BC_SPRITES_SETTINGS.scale * BC_SPRITES_SETTINGS.defaultSize);
                    UIObtainedResourcesPipe.update((s)=>{
                        s.gold -= 50;
                    });
                    incBuildingCount(1);
                }
            }
        }
        else if(!UIMainPipe.get().building)
        {
            if(vegetationObject)
            {
                try {
                    switch (vegetationObject.type) {
                        case "grass":
                            UIObtainedResourcesPipe.update((s)=>{
                                s.grass += vegetationObject.num;
                            });
                            break;
                        case "stone":
                            UIObtainedResourcesPipe.update((s)=>{
                                s.stone += vegetationObject.num;
                            });
                            break;
                        case "wood":
                            UIObtainedResourcesPipe.update((s)=>{
                                s.wood += vegetationObject.num;
                            });
                            break;
                        default:
                            break;
                    }
                    removeFromVegetation(t.x, t.y, vegetationObject.obj);
                } catch (error) {
                    
                }
            }
        }
    };
}

export async function initGame() {
    const app = new PIXI.Application();
    await app.init({ resizeTo: window, antialias: false });
    document.body.appendChild(app.canvas);
    setBC_APP(app);
    app.ticker.targetFPMS = 0.14;
    app.ticker.maxFPS = 140;

    await loadGameAssets();
    UIMainPipe.update((s) => {
        s.loadingAssets = false;
    });

    let world = new PIXI.Container();
    let viewport = new PIXI.Container();
    world.addChild(viewport);
    setBC_VIEWPORT(viewport);
    setBC_WORLD(world);
    viewport.isRenderGroup = true;
    app.stage.addChild(world);
    // world.tint = 0x00ffff;

    BC_CAMERA.position.x = Math.floor(PRNG() * 3242 - 372);
    BC_CAMERA.position.y = Math.floor(PRNG() * 1285 - 255);

    UICameraInfo.update((s)=>{
        s.position.x = BC_CAMERA.position.x;
        s.position.y = BC_CAMERA.position.y;
    })

    app.ticker.add(inputControllerTick);
    app.ticker.add(calculateViewportFromCamera);
    app.ticker.add(updateChunksVisibility);
    app.ticker.add(handleChunkFilling);
    app.ticker.add(profileFPS);
    app.ticker.add(handleBuildingsIncome);

    createKeyboardBinding("KeyW", "Hold", [moveVertically]);
    createKeyboardBinding("KeyS", "Hold", [moveVertically]);
    createKeyboardBinding("KeyA", "Hold", [moveHorizontally]);
    createKeyboardBinding("KeyD", "Hold", [moveHorizontally]);
}

function startGame() {
    setupGlobalInput();
    setupInGameSelector();
    BC_APP.ticker.add(handleDayNightCycle);
    BC_APP.ticker.add(handleSounds);
    ambientDay.play();
    ambientNight.play();
    ambientMusic.play();
}
