#pragma once
#include <cstdint>
#include <filesystem>
#include <optional>
#include <string>
#include <vector>
#include <mw/error.hpp>
#include "asset_store.h"
#include "authorization.h"
#include "data.h"
#include "image_processor.h"
#include "markdown_renderer.h"
#include "non_secret_random.h"
/// Validated common fields and staged files for a new card.
struct CreateCardInput
{
/// Human-readable card name.
std::string name;
/// Optional short Markdown description.
std::optional<std::string> short_description;
/// Optional long Markdown description.
std::optional<std::string> long_description;
/// Nonnegative rarity value.
std::int64_t rarity;
/// Complete private staging directory for this request.
std::filesystem::path staging_directory;
/// Staged front artwork path.
std::filesystem::path front;
/// Optional staged foil-control path.
std::optional<std::filesystem::path> foil;
/// Optional browser-rendered thumbnail for a foil card.
std::optional<std::filesystem::path> thumbnail;
/// Whether the request explicitly supplied a rarity field.
bool rarity_was_submitted = true;
};
/// Create-card input retained as the loose-card handler's explicit name.
using CreateLooseCardInput = CreateCardInput;
/// Requested handling for an existing required artwork asset.
enum class FrontAssetAction
{
KEEP,
REPLACE
};
/// Requested handling for an existing optional foil-control asset.
enum class FoilAssetAction
{
KEEP,
REPLACE,
REMOVE
};
/// Validated common fields and staged files for editing a loose card.
struct UpdateLooseCardInput
{
/// Card state observed while rendering the edit form or accepting it.
Card current_card;
/// Revision submitted by the browser for optimistic concurrency.
std::int64_t expected_revision;
/// Replacement human-readable card name.
std::string name;
/// Replacement optional short Markdown description.
std::optional<std::string> short_description;
/// Replacement optional long Markdown description.
std::optional<std::string> long_description;
/// Replacement nonnegative rarity value.
std::int64_t rarity;
/// Complete private staging directory for this request.
std::filesystem::path staging_directory;
/// Whether to retain or replace the front artwork.
FrontAssetAction front_action;
/// Whether to retain, replace, or remove the foil control.
FoilAssetAction foil_action;
/// Staged replacement front artwork, when requested.
std::optional<std::filesystem::path> front;
/// Staged replacement foil control, when requested.
std::optional<std::filesystem::path> foil;
/// Browser-rendered thumbnail for a changed resulting foil card.
std::optional<std::filesystem::path> thumbnail;
/// Whether the request explicitly supplied a rarity field.
bool rarity_was_submitted = true;
};
/// Coordinate image processing, persistence, and asset publication.
class CardService
{
public:
/// Construct a card creation service from its owned boundaries.
CardService(
DataSourceInterface& data_source,
NonSecretRandom& random,
ImageProcessor image_processor,
AssetStore asset_store);
/// Create a loose card after re-reading and authorizing its actor.
mw::E<std::string> createLooseCard(
std::int64_t actor_user_id, CreateLooseCardInput input);
/// Create a game card after re-reading and authorizing its actor.
mw::E<std::string> createGameCard(
std::int64_t actor_user_id,
CreateCardInput input,
std::string game_short_name,
std::int64_t expected_game_revision,
SubmittedGameFields submitted_fields,
const std::vector<std::int64_t>& series_ids);
/// Update a loose card after re-reading role and authorship.
mw::E<std::string> updateLooseCard(
std::int64_t actor_user_id, UpdateLooseCardInput input);
/// Update a game card after re-reading role and authorship.
mw::E<std::string> updateGameCard(
std::int64_t actor_user_id,
UpdateLooseCardInput input,
std::int64_t expected_game_revision,
SubmittedGameFields submitted_fields,
const std::vector<std::int64_t>& series_ids);
/// Delete a card only after re-reading an administrator actor.
mw::E<void> deleteCard(
std::int64_t actor_user_id, const Card& card);
private:
/// Create a loose or database-defined game card through one pipeline.
mw::E<std::string> createCard(
std::int64_t actor_user_id,
CreateCardInput input,
std::optional<std::string> game_short_name,
std::optional<std::int64_t> expected_game_revision,
SubmittedGameFields submitted_fields,
const std::vector<std::int64_t>& series_ids);
/// Update a loose or database-defined game card through one pipeline.
mw::E<std::string> updateCard(
std::int64_t actor_user_id,
UpdateLooseCardInput input,
std::optional<std::int64_t> expected_game_revision,
SubmittedGameFields submitted_fields,
const std::vector<std::int64_t>& series_ids);
DataSourceInterface& data_source_;
NonSecretRandom& random_;
ImageProcessor image_processor_;
AssetStore asset_store_;
MarkdownRenderer markdown_renderer_;
AuthorizationService authorization_;
};