/*
 *     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 { gameDifficulty, nilUuid, ServerVer, uuidRegex } from "../utils"
import { json as jsonMiddleware } from "body-parser"
import { enqueueEvent, newSession } from "../eventHandler"
import { _legacyBull, _theLastYardbirdScpc, controller } from "../controller"
import { log, LogLevel } from "../loggingInterop"
import { getConfig } from "../configSwizzleManager"
import type { GameChanger, RequestWithJwt } from "../types/types"
import { randomUUID } from "crypto"

const legacyContractRouter = Router()

legacyContractRouter.post(
    "/GetForPlay",
    jsonMiddleware(),
    (req: RequestWithJwt, res) => {
        if (!uuidRegex.test(req.body.id)) {
            res.status(400).end()
            return
        }

        const contractData =
            req.gameVersion === "h1" &&
            req.body.id === "42bac555-bbb9-429d-a8ce-f1ffdf94211c"
                ? _legacyBull
                : req.body.id === "ff9f46cf-00bd-4c12-b887-eac491c3a96d"
                ? _theLastYardbirdScpc
                : controller.resolveContract(req.body.id)

        if (!contractData) {
            log(
                LogLevel.ERROR,
                `Requested unknown contract in LGFP: ${req.body.id}`,
            )
            res.status(400).send("no such contract")
            return
        }

        if (!contractData.Data.GameChangers) {
            contractData.Data.GameChangers = []
        }

        for (const gamechangerId of req.body.extraGameChangerIds) {
            contractData.Data.GameChangers.push(gamechangerId)
        }

        if (contractData.Data.GameChangers.length > 0) {
            type GCPConfig = Record<string, GameChanger>

            const gameChangerData: GCPConfig = {
                ...getConfig<GCPConfig>("GameChangerProperties", true),
                ...getConfig<GCPConfig>("PeacockGameChangerProperties", true),
            }

            contractData.Data.GameChangerReferences = []

            for (const gameChangerId of contractData.Data.GameChangers) {
                const gameChanger = gameChangerData[gameChangerId]

                if (!gameChanger) {
                    log(
                        LogLevel.ERROR,
                        `Encountered unknown GameChanger id: ${gameChangerId}`,
                    )
                    res.status(500)
                    continue
                }

                gameChanger.Id = gameChangerId
                delete gameChanger.ObjectivesCategory

                contractData.Data.GameChangerReferences.push(gameChanger)

                if (gameChanger.Resource) {
                    contractData.Data.Bricks.push(...gameChanger.Resource)
                }

                if (gameChanger.Objectives) {
                    contractData.Data.Objectives?.push(
                        ...gameChanger.Objectives,
                    )
                }
            }
        }

        res.json(contractData)
    },
)

legacyContractRouter.post(
    "/Start",
    jsonMiddleware(),
    (req: RequestWithJwt, res) => {
        if (req.body.profileId !== req.jwt.unique_name) {
            res.status(400).end() // requested for different user id
            return
        }

        if (!uuidRegex.test(req.body.contractId)) {
            res.status(400).end()
            return
        }

        const c = controller.resolveContract(req.body.contractId)

        if (!c) {
            res.status(404).end()
            return
        }

        const contractSessionId = `${process.hrtime
            .bigint()
            .toString()}-${randomUUID()}`

        // all event stuff is handled in h3 event handler
        enqueueEvent(req.jwt.unique_name, {
            Version: ServerVer,
            IsReplicated: false,
            CreatedContract: null,
            Id: randomUUID(),
            Name: "ContractSessionMarker",
            UserId: nilUuid,
            ContractId: nilUuid,
            SessionId: null,
            ContractSessionId: contractSessionId,
            Timestamp: 0.0,
            Value: {
                Currency: {
                    ContractPaymentAllowed: true,
                    ContractPayment: null,
                },
            },
            Origin: null,
        })

        res.json(contractSessionId)

        newSession(
            contractSessionId,
            req.body.contractId,
            req.jwt.unique_name,
            gameDifficulty.normal,
            req.gameVersion,
        )
    },
)

export { legacyContractRouter }