// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3

#pragma once

#include <string>
#include <vector>
#include <functional>
#include <filesystem>

namespace dragonx {
namespace ui {
namespace schema {

/**
 * @brief Manages bundled and user-installed skins (unified TOML files)
 *
 * Responsibilities:
 *  - Enumerate bundled skins from res/themes/ directory (any .toml except ui.toml)
 *  - Enumerate user themes from ~/.config/ObsidianDragon/themes/<folder>/theme.toml
 *  - Import / remove user skins
 *  - Validate skin TOML structure before import
 *  - Track active skin ID in settings
 */
class SkinManager {
public:
    /**
     * @brief Metadata about an available skin
     */
    struct SkinInfo {
        std::string id;                 ///< Unique identifier (folder name or filename stem)
        std::string name;               ///< Display name from theme.name
        std::string author;             ///< Author from theme.author
        std::string path;               ///< Full filesystem path to the TOML file
        std::string directory;          ///< Folder containing theme.toml (empty for bundled flat files)
        std::string backgroundImagePath; ///< Resolved path to background image override (empty = use default)
        std::string logoPath;           ///< Resolved path to logo image override (empty = use default)
        bool dark = true;               ///< Dark mode flag from theme.dark
        bool bundled = true;            ///< true = shipped with app, false = user-installed
        bool valid = true;              ///< true if theme.toml passed validation
        std::string validationError;    ///< Error message if !valid
    };

    /**
     * @brief Result of a skin validation
     */
    struct ValidationResult {
        bool valid = false;
        std::string error;      ///< Error message if !valid
    };

    /**
     * @brief Get the singleton instance
     */
    static SkinManager& instance();

    /**
     * @brief Scan for available skins (bundled + user)
     *
     * Re-scans both the bundled res/ directory and the user skins directory.
     * Call this on startup and after import/remove operations.
     */
    void refresh();

    /**
     * @brief Get the list of available skins
     * @return Sorted list: bundled skins first (with "dragonx" at top), then user skins
     */
    const std::vector<SkinInfo>& available() const { return skins_; }

    /**
     * @brief Find a skin by ID
     * @return Pointer to SkinInfo, or nullptr if not found
     */
    const SkinInfo* findById(const std::string& id) const;

    /**
     * @brief Validate a skin TOML file
     * @param path Path to the TOML file
     * @return Validation result with error message if invalid
     *
     * Validation rules:
     *  1. File must be valid TOML
     *  2. Must contain [theme] table
     *  3. theme.name must be a non-empty string
     *  4. theme.palette must be a table with at least --primary and --background
     *  5. If [globals] exists, it must be a table
     */
    static ValidationResult validateSkinFile(const std::string& path);

    /**
     * @brief Import a skin file into the user skins directory
     * @param sourcePath Path to the source TOML file
     * @return true if imported successfully
     *
     * Validates the file first. Copies to user skins directory.
     * Calls refresh() on success.
     */
    bool importSkin(const std::string& sourcePath);

    /**
     * @brief Remove a user-installed skin
     * @param id Skin ID to remove
     * @return true if removed successfully
     *
     * Cannot remove bundled skins. Calls refresh() on success.
     */
    bool removeSkin(const std::string& id);

    /**
     * @brief Apply a skin by ID
     * @param id Skin ID to activate
     * @return true if skin was found and loaded
     *
     * Loads the skin file into UISchema and applies ImGui colors.
     */
    bool setActiveSkin(const std::string& id);

    /**
     * @brief Get the currently active skin ID
     */
    const std::string& activeSkinId() const { return activeSkinId_; }

    /**
     * @brief Get the bundled skins directory path
     */
    static std::string getBundledSkinsDirectory();

    /**
     * @brief Get the user skins directory path
     */
    static std::string getUserSkinsDirectory();

    /**
     * @brief Set callback invoked after skin changes (for image reloading)
     * @param cb Callback receiving backgroundImagePath and logoPath (empty = use default)
     */
    void setImageReloadCallback(std::function<void(const std::string& bgPath, const std::string& logoPath)> cb) {
        imageReloadCb_ = std::move(cb);
    }

    /**
     * @brief Re-resolve image paths from UISchema and trigger reload callback
     *
     * Called by UISchema hot-reload when [theme.images] values change.
     * Updates the active SkinInfo's image paths and fires imageReloadCb_.
     *
     * @param skinId  Active skin ID to update
     * @param tomlPath  Path to the TOML file whose images section changed
     */
    void resolveAndReloadImages(const std::string& skinId, const std::string& tomlPath);

    /**
     * @brief Enable/disable gradient background mode
     *
     * When enabled, theme backgrounds are replaced with their gradient
     * variants (e.g. "gradient_drgx_bg.png" instead of "drgx_bg.png").
     * Falls back to dark_gradient.png or light_gradient.png when no
     * theme-specific gradient exists.
     */
    void setGradientMode(bool enabled);
    bool isGradientMode() const { return gradientMode_; }

private:
    SkinManager() = default;
    ~SkinManager() = default;
    SkinManager(const SkinManager&) = delete;
    SkinManager& operator=(const SkinManager&) = delete;

    void scanDirectory(const std::string& dir, bool bundled);

    /// Resolve the image directory for a given skin
    std::filesystem::path resolveImgDir(const SkinInfo* skin) const;

    /// Given an original bg relative path and img dir, resolve the gradient variant
    std::string resolveGradientBg(const std::string& bgFilename,
                                  const std::filesystem::path& imgDir,
                                  bool isDark) const;

    /// Common helper: resolve bg (optionally gradient) and logo, fire callback
    void resolveAndFireCallback(SkinInfo* skin, const std::filesystem::path& imgDir);

    std::vector<SkinInfo> skins_;
    std::string activeSkinId_ = "dragonx";
    bool gradientMode_ = false;
    std::function<void(const std::string&, const std::string&)> imageReloadCb_;
};

} // namespace schema
} // namespace ui
} // namespace dragonx
