BareGit
#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_;
};