/*
 *     The Peacock Project - a HITMAN server replacement.
 *     Copyright (C) 2021-2023 The Peacock Project Team
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

import { Router } from "express"
import { RequestWithJwt } from "../types/types"
import { getConfig } from "../configSwizzleManager"
import { getDefaultSuitFor, uuidRegex } from "../utils"
import { json as jsonMiddleware } from "body-parser"
import { controller } from "../controller"
import { generateUserCentric, getSubLocationByName } from "../contracts/dataGen"
import { getUserData } from "../databaseHandler"
import { log, LogLevel } from "../loggingInterop"
import { createInventory } from "../inventory"
import { getFlag } from "../flags"
import { loadouts } from "../loadouts"

const legacyMenuDataRouter = Router()

legacyMenuDataRouter.get(
    "/stashpoint",
    (req: RequestWithJwt<{ contractid: string; slotname: string }>, res) => {
        // stashpoint?contractid=4e45e91a-94ca-4d89-89fc-1b250e608e73&stashpoint=&allowlargeitems=true&slotname=concealedweapon2
        if (!uuidRegex.test(req.query.contractid)) {
            res.status(400).send("contract id was not a uuid")
            return
        }

        const contractData = controller.resolveContract(req.query.contractid)
        if (!contractData) {
            res.status(404).send()
            return
        }

        const loadoutSlots = [
            "carriedweapon",
            "carrieditem",
            "concealedweapon",
            "disguise",
            "gear",
            "gear",
            "stashpoint",
        ]

        if (loadoutSlots.includes(req.query.slotname.slice(0, -1))) {
            req.query.slotid = req.query.slotname.slice(0, -1)
        } else {
            log(
                LogLevel.ERROR,
                `Unknown slotname in legacy stashpoint: ${req.query.slotname}`,
            )
            return
        }

        const userProfile = getUserData(req.jwt.unique_name, req.gameVersion)

        const inventory = createInventory(
            req.jwt.unique_name,
            req.gameVersion,
            userProfile.Extensions.entP,
        )

        const userCentricContract = generateUserCentric(
            contractData,
            req.jwt.unique_name,
            "h1",
        )

        const sublocation = getSubLocationByName(
            contractData.Metadata.Location,
            req.gameVersion,
        )

        const defaultLoadout = {
            2: "FIREARMS_HERO_PISTOL_TACTICAL_001_SU_SKIN01",
            3: getDefaultSuitFor(sublocation?.Properties?.ParentLocation),
            4: "TOKEN_FIBERWIRE",
            5: "PROP_TOOL_COIN",
        }

        const getLoadoutItem = (id: number) => {
            if (getFlag("loadoutSaving") === "LEGACY") {
                const dl = userProfile.Extensions.defaultloadout

                if (!dl) {
                    return defaultLoadout[id]
                }

                const forLocation = (userProfile.Extensions.defaultloadout ||
                    {})[sublocation?.Properties?.ParentLocation]

                if (!forLocation) {
                    return defaultLoadout[id]
                }

                return forLocation[id]
            } else {
                let dl = loadouts.getLoadoutFor("h1")

                if (!dl) {
                    dl = loadouts.createDefault("h1")
                }

                const forLocation =
                    dl.data[sublocation?.Properties?.ParentLocation]

                if (!forLocation) {
                    return defaultLoadout[id]
                }

                return forLocation[id]
            }
        }

        res.json({
            template: getConfig("LegacyStashpointTemplate", false),
            data: {
                ContractId: req.query.contractid,
                // the game actually only needs the loadoutdata from the requested slotid, but this is what IOI servers do
                LoadoutData: [...loadoutSlots.entries()].map(
                    ([slotid, slotname]) => ({
                        SlotName: slotname,
                        SlotId: slotid.toString(),
                        Items: inventory
                            .filter((item) => {
                                return (
                                    item.Unlockable.Properties.LoadoutSlot && // only display items
                                    (item.Unlockable.Properties.LoadoutSlot ===
                                        slotname || // display items for requested slot
                                        (slotname === "stashpoint" && // else: if stashpoint
                                            item.Unlockable.Properties
                                                .LoadoutSlot !== "disguise")) && // => display all non-disguise items
                                    (req.query.allowlargeitems === "true" ||
                                        item.Unlockable.Properties
                                            .LoadoutSlot !== "carriedweapon")
                                ) // not sure about this one
                            })
                            .map((item) => ({
                                Item: item,
                                ItemDetails: {
                                    Capabilities: [],
                                    StatList: item.Unlockable.Properties
                                        .Gameplay
                                        ? Object.entries(
                                              item.Unlockable.Properties
                                                  .Gameplay,
                                          ).map(([key, value]) => ({
                                              Name: key,
                                              Ratio: value,
                                          }))
                                        : [],
                                    PropertyTexts: [],
                                },
                                SlotId: slotid.toString(),
                                SlotName: slotname,
                            })),
                        Page: 0,
                        Recommended: getLoadoutItem(slotid)
                            ? {
                                  item: inventory.find(
                                      (item) =>
                                          item.Unlockable.Id ===
                                          getLoadoutItem(slotid),
                                  ),
                                  type: loadoutSlots[slotid],
                                  owned: true,
                              }
                            : null,
                        HasMore: false,
                        HasMoreLeft: false,
                        HasMoreRight: false,
                        OptionalData:
                            slotid === 6
                                ? {
                                      stashpoint: req.query.stashpoint,
                                      AllowLargeItems:
                                          req.query.allowlargeitems ||
                                          !req.query.stashpoint,
                                  }
                                : {},
                    }),
                ),
                Contract: userCentricContract.Contract,
                ShowSlotName: req.query.slotname,
                UserCentric: userCentricContract,
            },
        })
    },
)

legacyMenuDataRouter.get("/Safehouse", (req: RequestWithJwt, res, next) => {
    const template = getConfig("LegacySafehouseTemplate", false)

    // call /SafehouseCategory but rewrite the result a bit
    req.url = `/SafehouseCategory?page=0&type=${req.query.type}&subtype=`
    const originalJsonFunc = res.json
    res.json = function (originalData) {
        return originalJsonFunc.call(this, {
            template,
            data: {
                SafehouseData: originalData.data,
            },
        })
    }
    next()
})

legacyMenuDataRouter.get(
    "/debriefingchallenges",
    jsonMiddleware(),
    (
        req: RequestWithJwt<{ contractSessionId: string; contractId: string }>,
        res,
    ) => {
        // debriefingchallenges?contractSessionId=00000000000000-00000000-0000-0000-0000-000000000001&contractId=dd906289-7c32-427f-b689-98ae645b407f
        res.json({
            template: getConfig("LegacyDebriefingChallengesTemplate", false),
            data: {
                ChallengeData: {
                    // FIXME: This may not work correctly; I don't know the actual format so I'm assuming challenge tree
                    Children:
                        controller.challengeService.getChallengeTreeForContract(
                            req.query.contractId,
                            req.gameVersion,
                            req.jwt.unique_name,
                        ),
                },
            },
        })
    },
)

export { legacyMenuDataRouter }