#pragma once
#include <filesystem>
#include <memory>
#include <mutex>
#include <mw/database.hpp>
#include "data.h"
/// SQLite-backed implementation of the application persistence boundary.
class DataSourceSQLite final : public DataSourceInterface
{
public:
/// Destroy the data source after all transactions have ended.
~DataSourceSQLite() override = default;
/// Prevent copying a data source and its single owned connection.
DataSourceSQLite(const DataSourceSQLite&) = delete;
/// Prevent copy assignment of a data source connection.
DataSourceSQLite& operator=(const DataSourceSQLite&) = delete;
/// Open a SQLite database file without applying migrations.
static mw::E<std::unique_ptr<DataSourceSQLite>>
fromFile(const std::filesystem::path& database_path);
/// Return the stored schema version.
mw::E<std::int64_t> getSchemaVersion() const override;
/// Migrate an empty version-0 database to schema version 1.
mw::E<void> migrateSchema0To1() override;
/// Verify SQLite and application referential integrity after migration.
mw::E<void> checkIntegrity() const;
/// Start an immediate transaction with exclusive mutation ownership.
mw::E<std::unique_ptr<DataSourceTransactionInterface>>
beginTransaction() override;
/// Return all cards for the unpaginated index.
mw::E<std::vector<Card>> getCards(
GameContentScope scope) const override;
/// Return all cards authored by one user.
mw::E<std::vector<Card>> getCardsByCreator(
std::int64_t creator_user_id,
GameContentScope scope) const override;
/// Return every positive-rarity card in card-ID order.
mw::E<std::vector<Card>> getPoolCards() const override;
/// Return a card by its parsed identity.
mw::E<std::optional<Card>>
getCard(
const CardIdentity& identity,
GameContentScope scope) const override;
/// Return all database-defined games ordered by display name.
mw::E<std::vector<Game>> getGames(
GameContentScope scope) const override;
/// Return a complete, consistently read game definition.
mw::E<std::optional<GameDefinitionSnapshot>>
getGameDefinition(
const std::string& short_name,
GameContentScope scope) const override;
/// Return a card's definition and ordered custom values together.
mw::E<std::optional<CardGameFields>>
getCardFieldValues(
std::int64_t card_id,
GameContentScope scope) const override;
/// Return a user by internal identity.
mw::E<std::optional<User>> getUser(
std::int64_t user_id) const override;
/// Return a user by normalized immutable email identity.
mw::E<std::optional<User>> getUserByEmailKey(
const std::string& email_key) const override;
/// Return every user for administrator management.
mw::E<std::vector<User>> getUsers() const override;
/// Return a valid session joined with its current user.
mw::E<std::optional<SessionContext>> getSession(
const TokenHash& token_hash, std::int64_t now) const override;
/// Read one valid delivered challenge without consuming it.
mw::E<std::optional<AuthenticationChallenge>>
getAuthenticationChallenge(
const TokenHash& token_hash, std::int64_t now) const override;
/// Return a user's distinct collection entries.
mw::E<std::vector<CollectionEntry>> getCollection(
std::int64_t user_id,
GameContentScope scope) const override;
/// Return whether a user currently owns a card.
mw::E<bool> userOwnsCard(
std::int64_t user_id, std::int64_t card_id) const override;
/// Reconcile the one immutable configured administrator identity.
mw::E<User> reconcileAdministrator(
const std::string& email,
const std::string& email_key,
std::int64_t created_at,
std::int64_t pull_refresh_day) override;
/// Best-effort removal of obsolete authentication rows.
mw::E<void> cleanupAuthentication(std::int64_t now) override;
/// Return all series, ordered by game and name.
mw::E<std::vector<Series>> getSeries(
GameContentScope scope) const override;
/// Return one series by internal ID.
mw::E<std::optional<Series>>
getSeries(
std::int64_t series_id,
GameContentScope scope) const override;
/// Return the series memberships for one card.
mw::E<std::vector<std::int64_t>>
getCardSeries(std::int64_t card_id) const override;
protected:
/// Set the schema version inside a concrete migration transaction.
mw::E<void> setSchemaVersion(std::int64_t version) override;
private:
explicit DataSourceSQLite(std::unique_ptr<mw::SQLite> connection);
std::unique_ptr<mw::SQLite> connection_;
mutable std::mutex mutex_;
};