import express from 'express';
import { PlayerSystem } from '../../../../features/player';
import { MoneySystem } from '../../../../features/money';
import { MoneyChangeReasons } from '../../../../features/money/money_change_reasons';
import { ChatSystem } from '../../../../features/chat';
import { ItemTypeEntity } from '../../../../entities/item-type.entity';
import { getRepository } from 'typeorm';
import { inventorySystem } from '../../../../features/inventory';
import { ItemEntity } from '../../../../entities/item.entity';
import { LogSystem } from '../../../../core/log';
import { damageSystem } from '../../../../features/damage';
import { ChatColors } from '../../../../const/chat-colors';

export async function CharacterRefund(req: express.Request, res: express.Response): Promise<void> {
    const character = req.params.characterId;

    const by = req.body.byName;

    if (!character) {
        res.status(400).send('Missing key parameter');
        return;
    }

    if (!by) {
        res.status(400).send(`Missing issuer parameter`);
        return;
    }

    const characterId = Number(character);

    if (!characterId) {
        res.status(500).send('Unable to parse given key parameter');
        return;
    }

    const playerCharacter = PlayerSystem.GetPlayerFromCharacterId(characterId);

    if (!playerCharacter) {
        res.status(410).send(`Target character is not in-game`);
        return;
    }

    const isMoney = Number(req.body.isMoney);
    const amount = Number(req.body.amount);

    let alert = '';

    if (isMoney) {
        if (isNaN(amount) || amount <= 0) {
            res.status(400).send(`Invalid amount parameter`);
            return;
        }

        try {
            await MoneySystem.GivePlayerMoney(
                playerCharacter,
                amount,
                MoneyChangeReasons.UCP_REFUND,
                `${by} refunded ${playerCharacter.name} $${MoneySystem.FormatMoney(amount)}`,
            );
        } catch {
            res.status(500).send(`There was an error giving player money.`);
            return;
        }

        alert = `[UCP] ${by} refunded ${playerCharacter.name} (${playerCharacter.id}) $${MoneySystem.FormatMoney(amount)}`;
    } else {
        const itemTypeId = Number(req.body.itemTypeId);

        if (isNaN(itemTypeId) || !itemTypeId) {
            res.status(400).send(`Invalid item parameter`);
            return;
        }

        if (!playerCharacter.character.inventory) {
            res.status(400).send(`Target player doesn't have an inventory`);
            return;
        }

        const itemType = await getRepository(ItemTypeEntity).findOne(itemTypeId);
        if (!itemType) {
            res.status(400).send(`Invalid item type`);
            return;
        }

        if (!damageSystem.isPlayerAlive(playerCharacter)) {
            res.status(400).send(`Can't refund player when they aren't alive`);
            return;
        }

        try {
            await refund(by, playerCharacter, itemType, amount);
            alert = `[UCP] ${by} refunded ${playerCharacter.name} (${playerCharacter.id}) ${amount} ${itemType.name}`;
        } catch {
            res.status(500).send(`There was an error issuing the item.`);
            return;
        }
    }

    ChatSystem.AdminWarn(`` + alert);

    res.send(200);
}

async function refund(by: string, player: PlayerMpLoggedIn, itemType: ItemTypeEntity, amount: number): Promise<void> {
    await inventorySystem.acquireInventoryLock(player.character.inventory!.id, 'ucp_refund_rpc');

    const result = await getRepository(ItemEntity).insert({
        amount: amount * itemType.amount_multiplier,
        type_id: itemType.id,
        inventory_id: player.character.inventory!.id,
        data: itemType.default_item_data || {},
    });

    const entity = await getRepository(ItemEntity).findOne(result.raw.insertId);

    if (entity) {
        LogSystem.ItemEvent(entity, 'created', `Created by ${by}'s web refund to ${player.character.name}`, player);
    }

    await inventorySystem.syncItemsIntoInventory(player.character.inventory!, [result.raw.insertId]);
    inventorySystem.syncCharacterInventory(player);
    if (itemType.properties.weapon) {
        inventorySystem.syncWeaponInventory(player);
    }

    inventorySystem.applyInventoryClothes(player);
    inventorySystem.releaseInventoryLock(player.character.inventory!.id);
}
