/*****************************************************************************
 * Copyright (c) 2014-2025 OpenRCT2 developers
 *
 * For a complete list of all authors, please refer to contributors.md
 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
 *
 * OpenRCT2 is licensed under the GNU General Public License version 3.
 *****************************************************************************/

#include "WallRemoveAction.h"

#include "../Cheats.h"
#include "../GameState.h"
#include "../OpenRCT2.h"
#include "../core/MemoryStream.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../world/Location.hpp"
#include "../world/TileElementsView.h"
#include "../world/tile_element/WallElement.h"

namespace OpenRCT2::GameActions
{
    WallRemoveAction::WallRemoveAction(const CoordsXYZD& loc)
        : _loc(loc)
    {
    }

    void WallRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor)
    {
        visitor.Visit(_loc);
    }

    void WallRemoveAction::Serialise(DataSerialiser& stream)
    {
        GameAction::Serialise(stream);

        stream << DS_TAG(_loc);
    }

    Result WallRemoveAction::Query() const
    {
        Result res = Result();
        res.Cost = 0;
        res.Expenditure = ExpenditureType::landscaping;

        if (!LocationValid(_loc))
        {
            return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP);
        }

        const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST;
        if (!isGhost && gLegacyScene != LegacyScene::scenarioEditor && !getGameState().cheats.sandboxMode
            && !MapIsLocationOwned(_loc))
        {
            return Result(Status::NotOwned, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK);
        }

        TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost);
        if (wallElement == nullptr)
        {
            return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS);
        }

        res.Cost = 0;
        return res;
    }

    Result WallRemoveAction::Execute() const
    {
        Result res = Result();
        res.Cost = 0;
        res.Expenditure = ExpenditureType::landscaping;

        const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST;

        TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost);
        if (wallElement == nullptr)
        {
            return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS);
        }

        res.Position.x = _loc.x + 16;
        res.Position.y = _loc.y + 16;
        res.Position.z = _loc.z;

        wallElement->RemoveBannerEntry();
        MapInvalidateTileZoom1({ _loc, wallElement->GetBaseZ(), (wallElement->GetBaseZ()) + 72 });
        TileElementRemove(wallElement);

        return res;
    }

    TileElement* WallRemoveAction::GetFirstWallElementAt(const CoordsXYZD& location, bool isGhost) const
    {
        for (auto* wallElement : TileElementsView<WallElement>(location))
        {
            if (wallElement->GetBaseZ() != location.z)
                continue;
            if (wallElement->GetDirection() != location.direction)
                continue;
            if (wallElement->IsGhost() != isGhost)
                continue;

            return wallElement->as<TileElement>();
        }
        return nullptr;
    }
} // namespace OpenRCT2::GameActions
