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

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

    const userDB = await getUserByAccessToken(response);
    if(userDB === 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.planetId));
    if(!userPlanet) {
        return new Response(
            JSON.stringify({
                code: 404,
                message: "Not Found",
                error: "Planet not found"
            }), { status: 404 }
        )
    }

    const user = userPlanet.system.data.ownedBy;

    if(!user.id.equals(userDB._id)) {
        return new Response(
            JSON.stringify({
                code: 403,
                message: "Forbidden",
                error: "You don't own this planet"
            }), { status: 403 }
        )
    }
    
    const researchId = body.research as string;
    const research = await getResearchById(researchId);

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

    
    // check requirements
    // buildings
    const buildings = userPlanet.buildings;
    for(const buildingReq of research.requirements.buildings) {
        if((buildings.buildings.find((building) => building.data.id === buildingReq.id)?.level ?? 0) < buildingReq.level) {
            return new Response(
                JSON.stringify({
                    code: 400,
                    message: "Bad Request",
                    error: `${buildingReq.id} level ${buildingReq.level} required, found ${buildings.buildings.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0}`
                }), { status: 400 }
            )
        }
    };

    // research
    const playerResearch = user.research.research;
    for(const researchReq of research.requirements.research) {
        if((playerResearch.find((research) => research.id === researchReq.id)?.level ?? 0) < researchReq.level) {
            return new Response(
                JSON.stringify({
                    code: 400,
                    message: "Bad Request",
                    error: `${researchReq.id} level ${researchReq.level} required, found ${playerResearch.filter((research) => research.id === researchReq.id)[0].level}`
                }), { status: 400 }
            )
        }
    };

    // resources
    const resources = await userPlanet.resources.calculateCurrentAvailableResources();
    if(!resources) {
        return new Response(
            JSON.stringify({
                code: 500,
                message: "Internal Server Error",
                error: "Failed to get resources"
            }), { status: 500 }
        )
    }
    
    const playerCurrentResearch = playerResearch.filter((element: any) => element.id === researchId)[0];
    const level = playerCurrentResearch ? playerCurrentResearch.level : 0;
    const newResources = structuredClone(resources);
    const missingResources: Array<{ id: string, required: number, available: number }> = [];
    for(const resource of research.requirements.resources) {
        const res = resources.filter((element) => element.id === resource.id)[0];
        const cost = playerCurrentResearch ? resource.amount * Math.pow(research.multiplier, level) : resource.amount;
        
        if(res.amount < cost) {
            missingResources.push({
                id: resource.id,
                required: cost,
                available: res.amount
            });
            break;
        }
        else newResources.filter((element) => element.id === resource.id)[0].amount -= cost;
    };

    if(missingResources.length > 0) {
        return new Response(
            JSON.stringify({
                code: 400,
                message: "Bad Request",
                data: missingResources
            }), { status: 400 }
        )
    }
    
    userPlanet.resources.updateAmount(newResources.map(res => { return { id: res.id, amount: res.amount } }));
    user.research.addResearch({
        id: researchId,
        level: level + 1,
        data: research
    });

    await userPlanet.resources.sync();
    await user.research.sync();

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