import { type APIRoute } from "astro";
import validateAccessToken from "../../../lib/utils/validateAccessToken";
import { getUserByAccessToken } from "../../../lib/db/users";
import { ObjectId } from "mongodb";
import locationManager from "../../../lib/classes/managers/LocationManager";
import Building from "../../../lib/classes/Building";
import { getAllResources } from "../../../lib/db/resources";

export const POST: APIRoute = async({ request }) => {
    const response = await validateAccessToken(request);
    if(response instanceof Response) return response;

    const user = await getUserByAccessToken(response);
    if(user === null) {
        return new Response(
            JSON.stringify({
                code: 401,
                message: "Unauthorized"
            }), { status: 401 }
        )
    }

    let body;
    try {
        body = await request.json()
    } catch(e) {
        return new Response(
            JSON.stringify({
                code: 400,
                message: "Bad Request",
                error: "Invalid JSON body"
            }), { status: 400 }
        )
    }

    const userPlanet = locationManager.getPlanet(new ObjectId(body.planet));
    
    if(!userPlanet) {
        return new Response(
            JSON.stringify({
                code: 400,
                message: "Bad Request",
                error: "Invalid planet ID"
            }), { status: 400 }
        )
    }

    const buildingId: string = body.building;

    const buildingObj = userPlanet.buildings.buildingsDB.find(b => b.id === buildingId);

    if(!buildingObj) return new Response(
        JSON.stringify({
            code: 400,
            message: "Bad Request",
            error: "Invalid building ID"
        }), { status: 400 }
    )

    const building = new Building(userPlanet.buildings, buildingObj, 1);

    const requirements = await building.checkRequirements();
    const resources = await building.checkRequiredResources((userPlanet.buildings.getBuildingById(buildingId)?.level ?? 0));

    if(!requirements.canBuild || !resources) {
        return new Response(
            JSON.stringify({
                code: 400,
                message: "Bad Request",
                error: `${requirements.error} | ${resources ? "" : "Not enough resources"}`
            }), { status: 400 }
        )
    }

    const resourcesDiff = await userPlanet.resources.getDifference(building.data.requirements.resources.map(res => {
        return {
            id: res.id,
            amount: Math.pow(building.data.multiplier, (userPlanet.buildings.getBuildingById(buildingId)?.level ?? 0)) * res.amount
        }
    }));

    const resourceDB = await getAllResources();
    const resourcesAfter = resourcesDiff.map(res => {
        const data = resourceDB.find(r => r.id === res.id);

        if(!data) throw new Error("Resource not found");

        return {
            id: res.id,
            amount: res.amount,
            lastUpdated: res.lastUpdated,
            perHourMiningRate: res.perHourMiningRate,
            data
        }
    });

    userPlanet.resources.setAmount(resourcesAfter.map(res => { return { id: res.id, amount: res.amount } }));
    userPlanet.buildings.addBuilding(building);
    if(building.data.category === "mines") {
        switch(building.data.id) {
            case 'coal-mine':
                const coalResource = userPlanet.resources.resources.find(r => r.id === "coal");
                if(coalResource) coalResource.perHourMiningRate += 10;
                break;
            case 'iron-mine':
                const ironResource = userPlanet.resources.resources.find(r => r.id === "iron");
                if(ironResource) ironResource.perHourMiningRate += 10;
                break;
            case 'gold-mine':
                const goldResource = userPlanet.resources.resources.find(r => r.id === "gold");
                if(goldResource) goldResource.perHourMiningRate += 10;
                break;
        }
    }

    await userPlanet.buildings.sync();
    await userPlanet.resources.sync();
    userPlanet.energy.update();

    return new Response(
        JSON.stringify({
            code: 200,
            message: "OK"
        }), { status: 200 }
    );
}