#ifndef CONFIG_H
#define CONFIG_H

#include <sqlite3.h>
#include <time.h>
#include <stddef.h>
#include <cjson/cJSON.h>

// Configuration system constants
#define CONFIG_KEY_MAX_LENGTH 64
#define CONFIG_VALUE_MAX_LENGTH 512
#define CONFIG_DESCRIPTION_MAX_LENGTH 256
#define CONFIG_XDG_DIR_NAME "c-relay"
#define CONFIG_FILE_NAME "c_relay_config_event.json"
#define CONFIG_PRIVKEY_ENV "C_RELAY_CONFIG_PRIVKEY"
#define NOSTR_PUBKEY_HEX_LENGTH 64
#define NOSTR_PRIVKEY_HEX_LENGTH 64
#define NOSTR_EVENT_ID_HEX_LENGTH 64
#define NOSTR_SIGNATURE_HEX_LENGTH 128

// Protocol and implementation constants (hardcoded - should NOT be configurable)
#define SUBSCRIPTION_ID_MAX_LENGTH 64
#define CLIENT_IP_MAX_LENGTH 64
#define RELAY_NAME_MAX_LENGTH 128
#define RELAY_DESCRIPTION_MAX_LENGTH 1024
#define RELAY_URL_MAX_LENGTH 256
#define RELAY_CONTACT_MAX_LENGTH 128
#define RELAY_PUBKEY_MAX_LENGTH 65

// Default configuration values (used as fallbacks if database config fails)
#define DEFAULT_DATABASE_PATH "db/c_nostr_relay.db"
#define DEFAULT_PORT 8888
#define DEFAULT_HOST "127.0.0.1"
#define MAX_CLIENTS 100
#define MAX_SUBSCRIPTIONS_PER_CLIENT 20
#define MAX_TOTAL_SUBSCRIPTIONS 5000
#define MAX_FILTERS_PER_SUBSCRIPTION 10

// Configuration types
typedef enum {
    CONFIG_TYPE_SYSTEM = 0,
    CONFIG_TYPE_USER = 1,
    CONFIG_TYPE_RUNTIME = 2
} config_type_t;

// Configuration data types
typedef enum {
    CONFIG_DATA_STRING = 0,
    CONFIG_DATA_INTEGER = 1,
    CONFIG_DATA_BOOLEAN = 2,
    CONFIG_DATA_JSON = 3
} config_data_type_t;

// Configuration validation result
typedef enum {
    CONFIG_VALID = 0,
    CONFIG_INVALID_TYPE = 1,
    CONFIG_INVALID_RANGE = 2,
    CONFIG_INVALID_FORMAT = 3,
    CONFIG_MISSING_REQUIRED = 4
} config_validation_result_t;

// Configuration entry structure
typedef struct {
    char key[CONFIG_KEY_MAX_LENGTH];
    char value[CONFIG_VALUE_MAX_LENGTH];
    char description[CONFIG_DESCRIPTION_MAX_LENGTH];
    config_type_t config_type;
    config_data_type_t data_type;
    int is_sensitive;
    int requires_restart;
    time_t created_at;
    time_t updated_at;
} config_entry_t;

// Configuration manager state
typedef struct {
    sqlite3* db;
    sqlite3_stmt* get_config_stmt;
    sqlite3_stmt* set_config_stmt;
    sqlite3_stmt* log_change_stmt;
    
    // Configuration loading status
    int file_config_loaded;
    int database_config_loaded;
    time_t last_reload;
    
    // XDG configuration directory
    char config_dir_path[512];
    char config_file_path[600];
} config_manager_t;

// Global configuration manager instance
extern config_manager_t g_config_manager;

// ================================
// CORE CONFIGURATION FUNCTIONS
// ================================

// Initialize configuration system
int init_configuration_system(void);

// Cleanup configuration system
void cleanup_configuration_system(void);

// Load configuration from all sources (file -> database -> defaults)
int load_configuration(void);

// Apply loaded configuration to global variables
int apply_configuration_to_globals(void);

// ================================
// DATABASE CONFIGURATION FUNCTIONS
// ================================

// Initialize database prepared statements
int init_config_database_statements(void);

// Get configuration value from database
int get_database_config(const char* key, char* value, size_t value_size);

// Set configuration value in database
int set_database_config(const char* key, const char* new_value, const char* changed_by);

// Load all configuration from database
int load_config_from_database(void);

// ================================
// FILE CONFIGURATION FUNCTIONS
// ================================

// Get XDG configuration directory path
int get_xdg_config_dir(char* path, size_t path_size);

// Check if configuration file exists
int config_file_exists(void);

// Load configuration from file
int load_config_from_file(void);

// Validate and apply Nostr configuration event
int validate_and_apply_config_event(const cJSON* event);

// Validate Nostr event structure
int validate_nostr_event_structure(const cJSON* event);

// Validate configuration tags array
int validate_config_tags(const cJSON* tags);

// Extract and apply configuration tags to database
int extract_and_apply_config_tags(const cJSON* tags);

// ================================
// CONFIGURATION ACCESS FUNCTIONS
// ================================

// Get configuration value (checks all sources: file -> database -> environment -> defaults)
const char* get_config_value(const char* key);

// Get configuration value as integer
int get_config_int(const char* key, int default_value);

// Get configuration value as boolean
int get_config_bool(const char* key, int default_value);

// Set configuration value (updates database)
int set_config_value(const char* key, const char* value);

// ================================
// CONFIGURATION VALIDATION
// ================================

// Validate configuration value
config_validation_result_t validate_config_value(const char* key, const char* value);

// Log validation error
void log_config_validation_error(const char* key, const char* value, const char* error);

// ================================
// UTILITY FUNCTIONS
// ================================

// Convert config type enum to string
const char* config_type_to_string(config_type_t type);

// Convert config data type enum to string
const char* config_data_type_to_string(config_data_type_t type);

// Convert string to config type enum
config_type_t string_to_config_type(const char* str);

// Convert string to config data type enum
config_data_type_t string_to_config_data_type(const char* str);

// Check if configuration key requires restart
int config_requires_restart(const char* key);

// ================================
// NOSTR EVENT GENERATION FUNCTIONS
// ================================

// Generate configuration file with valid Nostr event if it doesn't exist
int generate_config_file_if_missing(void);

// Create a valid Nostr configuration event from database values
cJSON* create_config_nostr_event(const char* privkey_hex);

// Generate a random private key (32 bytes as hex string)
int generate_random_privkey(char* privkey_hex, size_t buffer_size);

// Derive public key from private key (using secp256k1)
int derive_pubkey_from_privkey(const char* privkey_hex, char* pubkey_hex, size_t buffer_size);

// Create Nostr event ID (SHA256 of serialized event data)
int create_nostr_event_id(const cJSON* event, char* event_id_hex, size_t buffer_size);

// Sign Nostr event (using secp256k1 Schnorr signature)
int sign_nostr_event(const cJSON* event, const char* privkey_hex, char* signature_hex, size_t buffer_size);

// Write configuration event to file
int write_config_event_to_file(const cJSON* event);

#endif // CONFIG_H