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 Ship from "../../../lib/classes/Ship";
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 }
        )
    }

    if(!body.planet || !body.ship || !body.amount) {
        return new Response(
            JSON.stringify({
                code: 400,
                message: "Bad Request",
                error: "Missing required fields: planet, ship, amount"
            }), { status: 400 }
        )
    }

    const amount = parseInt(body.amount);
    if(isNaN(amount) || amount <= 0) {
        return new Response(
            JSON.stringify({
                code: 400,
                message: "Bad Request",
                error: "Invalid amount"
            }), { 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 shipDB = userPlanet.ships.shipsDB.find(s => s.id === body.ship);

    if(!shipDB) {
        return new Response(
            JSON.stringify({
                code: 400,
                message: "Bad Request",
                error: "Invalid ship ID"
            }), { status: 400 }
        )
    }
    
    const ship = new Ship(userPlanet.ships, shipDB, amount);

    const requirements = await ship.checkRequirements();
    const resources = await ship.checkRequiredResources();

    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(ship.data.requirements.resources.map(res => {
        return {
            id: res.id,
            amount: amount * 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.updateAmount(resourcesAfter.map(res => { return { id: res.id, amount: res.amount } }));
    userPlanet.ships.addShips(ship.data.id, amount);

    await userPlanet.ships.sync();
    await userPlanet.resources.sync();

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