#ifndef USER_MANAGER_H
#define USER_MANAGER_H

#include <string>
#include <vector>
#include <map>
#include <memory>
#include <mutex>
#include <functional>

#ifdef ENABLE_PAM_AUTH
#include "pam_auth.h"
#endif

/**
 * @brief User information structure
 */
struct UserInfo {
    std::string id;                    ///< Unique user ID
    std::string username;              ///< Username (unique)
    std::string email;                 ///< Email address
    std::string passwordHash;          ///< Hashed password
    std::string role;                  ///< User role (admin, user, etc.)
    std::vector<std::string> permissions;  ///< User permissions
    std::vector<std::string> apiKeys;  ///< User's API keys
    bool active;                       ///< Account active status
    int64_t createdAt;                 ///< Account creation timestamp
    int64_t lastLoginAt;               ///< Last login timestamp
    int64_t passwordChangedAt;         ///< Password change timestamp
    std::string createdBy;             ///< Who created this user
};

/**
 * @brief API key information structure
 */
struct ApiKeyInfo {
    std::string keyId;                 ///< Unique key ID
    std::string keyHash;               ///< Hashed API key
    std::string name;                  ///< Key name/description
    std::string userId;                ///< Owner user ID
    std::vector<std::string> permissions;  ///< Key permissions
    bool active;                       ///< Key active status
    int64_t createdAt;                 ///< Key creation timestamp
    int64_t lastUsedAt;                ///< Last used timestamp
    int64_t expiresAt;                 ///< Key expiration timestamp (0 = no expiration)
    std::string createdBy;             ///< Who created this key
};

/**
 * @brief Authentication result structure
 */
struct AuthResult {
    bool success;                       ///< Authentication success
    std::string userId;                 ///< User ID if successful
    std::string username;               ///< Username if successful
    std::string role;                   ///< User role if successful
    std::vector<std::string> permissions;  ///< User permissions if successful
    std::string errorMessage;           ///< Error message if failed
    std::string errorCode;              ///< Error code for API responses
};

/**
 * @brief User management system
 *
 * This class provides user authentication, authorization, and management
 * functionality for the stable-diffusion.cpp-rest server. It supports
 * local user storage, API key management, and role-based access control.
 */
class UserManager {
public:
    /**
     * @brief Authentication methods enumeration
     */
    enum class AuthMethod {
        NONE,           ///< No authentication required
        JWT,            ///< JWT token authentication
        API_KEY,        ///< API key authentication
        UNIX,           ///< Unix system authentication
        PAM,            ///< PAM authentication
        OPTIONAL        ///< Authentication optional (guest access allowed)
    };

    /**
     * @brief User roles enumeration
     */
    enum class UserRole {
        GUEST,          ///< Guest user (no authentication)
        USER,           ///< Regular user
        ADMIN,          ///< Administrator
        SERVICE         ///< Service account
    };

    /**
     * @brief Standard permissions
     */
    struct Permissions {
        static const std::string READ;           ///< Read access to models and status
        static const std::string GENERATE;       ///< Generate images
        static const std::string QUEUE_MANAGE;   ///< Manage generation queue
        static const std::string MODEL_MANAGE;   ///< Load/unload models
        static const std::string USER_MANAGE;    ///< Manage other users
        static const std::string ADMIN;          ///< Full administrative access
    };

    /**
     * @brief Construct a new User Manager object
     *
     * @param dataDir Directory for storing user data
     * @param authMethod Primary authentication method
     * @param enableUnixAuth Enable Unix authentication
     */
    explicit UserManager(const std::string& dataDir,
                        AuthMethod authMethod = AuthMethod::JWT);

    /**
     * @brief Destroy the User Manager object
     */
    ~UserManager();

    /**
     * @brief Initialize the user manager
     *
     * @return true if initialization successful, false otherwise
     */
    bool initialize();

    /**
     * @brief Shutdown the user manager
     */
    void shutdown();

    /**
     * @brief Authenticate user with username and password
     *
     * @param username Username
     * @param password Plain text password
     * @return AuthResult Authentication result
     */
    AuthResult authenticateUser(const std::string& username, const std::string& password);

    /**
     * @brief authenticate user with Unix system
     *
     * @param username Unix username
     * @param password Unix password (used when PAM is enabled)
     * @return AuthResult Authentication result
     */
    AuthResult authenticateUnix(const std::string& username, const std::string& password = "");

    /**
     * @brief authenticate user with PAM
     *
     * @param username Username
     * @param password Plain text password
     * @return AuthResult Authentication result
     */
    AuthResult authenticatePam(const std::string& username, const std::string& password);

    /**
     * @brief Authenticate with API key
     *
     * @param apiKey API key string
     * @return AuthResult Authentication result
     */
    AuthResult authenticateApiKey(const std::string& apiKey);

    /**
     * @brief Create a new user
     *
     * @param username Username
     * @param password Plain text password
     * @param email Email address
     * @param role User role
     * @param createdBy User ID of creator
     * @return std::pair<bool, std::string> Success flag and user ID or error message
     */
    std::pair<bool, std::string> createUser(const std::string& username,
                                           const std::string& password,
                                           const std::string& email,
                                           UserRole role = UserRole::USER,
                                           const std::string& createdBy = "system");

    /**
     * @brief Update user information
     *
     * @param userId User ID
     * @param updates Map of fields to update
     * @return std::pair<bool, std::string> Success flag and message
     */
    std::pair<bool, std::string> updateUser(const std::string& userId,
                                           const std::map<std::string, std::string>& updates);

    /**
     * @brief Delete a user
     *
     * @param userId User ID to delete
     * @param requestingUserId User ID making the request
     * @return std::pair<bool, std::string> Success flag and message
     */
    std::pair<bool, std::string> deleteUser(const std::string& userId,
                                           const std::string& requestingUserId);

    /**
     * @brief Change user password
     *
     * @param userId User ID
     * @param oldPassword Current password (can be empty for admin)
     * @param newPassword New password
     * @param requestingUserId User ID making the request
     * @return std::pair<bool, std::string> Success flag and message
     */
    std::pair<bool, std::string> changePassword(const std::string& userId,
                                               const std::string& oldPassword,
                                               const std::string& newPassword,
                                               const std::string& requestingUserId);

    /**
     * @brief Get user information
     *
     * @param userId User ID
     * @return UserInfo User information, empty if not found
     */
    UserInfo getUserInfo(const std::string& userId);

    /**
     * @brief Get user information by username
     *
     * @param username Username
     * @return UserInfo User information, empty if not found
     */
    UserInfo getUserInfoByUsername(const std::string& username);

    /**
     * @brief List all users
     *
     * @param requestingUserId User ID making the request
     * @return std::vector<UserInfo> List of users (limited for non-admins)
     */
    std::vector<UserInfo> listUsers(const std::string& requestingUserId);

    /**
     * @brief Create API key for user
     *
     * @param userId User ID
     * @param name Key name/description
     * @param permissions Key permissions
     * @param expiresAt Expiration timestamp (0 = no expiration)
     * @param createdBy User ID creating the key
     * @return std::pair<bool, std::string> Success flag and API key or error message
     */
    std::pair<bool, std::string> createApiKey(const std::string& userId,
                                              const std::string& name,
                                              const std::vector<std::string>& permissions,
                                              int64_t expiresAt = 0,
                                              const std::string& createdBy = "system");

    /**
     * @brief Revoke API key
     *
     * @param keyId API key ID
     * @param requestingUserId User ID making the request
     * @return std::pair<bool, std::string> Success flag and message
     */
    std::pair<bool, std::string> revokeApiKey(const std::string& keyId,
                                             const std::string& requestingUserId);

    /**
     * @brief List API keys for user
     *
     * @param userId User ID
     * @param requestingUserId User ID making the request
     * @return std::vector<ApiKeyInfo> List of API keys
     */
    std::vector<ApiKeyInfo> listApiKeys(const std::string& userId,
                                        const std::string& requestingUserId);

    /**
     * @brief Get API key information
     *
     * @param keyId API key ID
     * @param requestingUserId User ID making the request
     * @return ApiKeyInfo API key information, empty if not found
     */
    ApiKeyInfo getApiKeyInfo(const std::string& keyId,
                             const std::string& requestingUserId);

    /**
     * @brief Update API key last used timestamp
     *
     * @param keyId API key ID
     */
    void updateApiKeyLastUsed(const std::string& keyId);

    /**
     * @brief Check if user has permission
     *
     * @param userId User ID
     * @param permission Permission to check
     * @return true if user has permission, false otherwise
     */
    bool hasPermission(const std::string& userId, const std::string& permission);

    /**
     * @brief Check if user has any of the specified permissions
     *
     * @param userId User ID
     * @param permissions List of permissions to check
     * @return true if user has any permission, false otherwise
     */
    bool hasAnyPermission(const std::string& userId,
                         const std::vector<std::string>& permissions);

    /**
     * @brief Get user role as string
     *
     * @param role User role enum
     * @return std::string Role string
     */
    static std::string roleToString(UserRole role);

    /**
     * @brief Parse role from string
     *
     * @param roleStr Role string
     * @return UserRole Role enum
     */
    static UserRole stringToRole(const std::string& roleStr);

    /**
     * @brief Get default permissions for role
     *
     * @param role User role
     * @return std::vector<std::string> List of permissions
     */
    static std::vector<std::string> getDefaultPermissions(UserRole role);

    /**
     * @brief Set authentication method
     *
     * @param method Authentication method
     */
    void setAuthMethod(AuthMethod method);

    /**
     * @brief Get current authentication method
     *
     * @return AuthMethod Current authentication method
     */
    AuthMethod getAuthMethod() const;


    /**
     * @brief Enable or disable PAM authentication
     *
     * @param enable Enable PAM authentication
     */
    void setPamAuthEnabled(bool enable);

    /**
     * @brief Check if PAM authentication is enabled
     *
     * @return true if PAM authentication is enabled, false otherwise
     */
    bool isPamAuthEnabled() const;

    /**
     * @brief Get user statistics
     *
     * @return std::map<std::string, int> Statistics map
     */
    std::map<std::string, int> getStatistics();

private:
    std::string m_dataDir;                    ///< Data directory
    AuthMethod m_authMethod;                  ///< Current auth method
    bool m_pamAuthEnabled;                    ///< PAM auth enabled flag
    std::map<std::string, UserInfo> m_users;  ///< User storage (username -> UserInfo)
    std::map<std::string, ApiKeyInfo> m_apiKeys; ///< API key storage (keyId -> ApiKeyInfo)
    std::map<std::string, std::string> m_apiKeyMap; ///< API key hash -> keyId mapping
    mutable std::mutex m_mutex;               ///< Thread safety mutex
#ifdef ENABLE_PAM_AUTH
    std::unique_ptr<PamAuth> m_pamAuth;      ///< PAM authentication instance
#endif

    /**
     * @brief Hash password using bcrypt
     *
     * @param password Plain text password
     * @return std::string Hashed password
     */
    std::string hashPassword(const std::string& password);

    /**
     * @brief Verify password against hash
     *
     * @param password Plain text password
     * @param hash Password hash
     * @return true if password matches, false otherwise
     */
    bool verifyPassword(const std::string& password, const std::string& hash);

    /**
     * @brief Hash API key
     *
     * @param apiKey Plain text API key
     * @return std::string Hashed API key
     */
    std::string hashApiKey(const std::string& apiKey);

    /**
     * @brief Generate unique user ID
     *
     * @return std::string Unique user ID
     */
    std::string generateUserId();

    /**
     * @brief Generate unique API key ID
     *
     * @return std::string Unique API key ID
     */
    std::string generateKeyId();

    /**
     * @brief Save user data to file
     *
     * @return true if successful, false otherwise
     */
    bool saveUserData();

    /**
     * @brief Load user data from file
     *
     * @return true if successful, false otherwise
     */
    bool loadUserData();

    /**
     * @brief Save API key data to file
     *
     * @return true if successful, false otherwise
     */
    bool saveApiKeyData();

    /**
     * @brief Load API key data from file
     *
     * @return true if successful, false otherwise
     */
    bool loadApiKeyData();

    /**
     * @brief Get current timestamp
     *
     * @return int64_t Current timestamp
     */
    static int64_t getCurrentTimestamp();

    /**
     * @brief Validate username format
     *
     * @param username Username to validate
     * @return true if valid, false otherwise
     */
    static bool validateUsername(const std::string& username);

    /**
     * @brief Validate password strength
     *
     * @param password Password to validate
     * @return true if valid, false otherwise
     */
    static bool validatePassword(const std::string& password);

    /**
     * @brief Validate email format
     *
     * @param email Email to validate
     * @return true if valid, false otherwise
     */
    static bool validateEmail(const std::string& email);

    /**
     * @brief Check if user can manage target user
     *
     * @param requestingUserId User making request
     * @param targetUserId Target user
     * @return true if allowed, false otherwise
     */
    bool canManageUser(const std::string& requestingUserId, const std::string& targetUserId);
};

#endif // USER_MANAGER_H