#include "..\script_component.hpp"

/*
 * Author: IDSolutions
 * Initialize message store for SMS/messaging management
 *
 * Arguments:
 * N/A
 *
 * Return Value:
 * Message Store Object
 *
 * Examples:
 * [] call forge_server_phone_fnc_initMessageStore
 *
 * Public: No
 */

GVAR(MessageStore) = createHashMapObject [[
    ["#type", "IMessageStore"],
    ["#create", {
        GVAR(MessageRegistry) = createHashMap; // uid -> HashMap of threads
        diag_log "[FORGE:Server:Phone] Message Store Initialized!";
    }],
    ["init", {
        params [["_uid", "", [""]]];

        if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Phone:Message] Empty UID provided to init"; createHashMap };

        // Initialize message registry for player (threads organized by other participant)
        GVAR(MessageRegistry) set [_uid, createHashMap];

        // Load existing messages from database into registry
        _self call ["loadMessagesFromDatabase", [_uid]];

        diag_log format ["[FORGE:Server:Phone:Message] Messages initialized for %1", _uid];
        true
    }],
    ["loadMessagesFromDatabase", {
        params [["_uid", "", [""]]];

        if (_uid isEqualTo "") exitWith {
            diag_log "[FORGE:Server:Phone:Message] Invalid UID provided for message loading";
            false
        };

        try {
            private _messageData = [format ["%1:messages", _uid]] call dragonfly_db_fnc_lrange;

            if (!isNil "_messageData" && { count _messageData > 0 }) then {
                private _threadMap = createHashMap;

                // Parse messages and organize them into threads
                {
                    private _message = _self call ["toHashMap", [_x]];
                    _message set ["id", _forEachIndex];

                    private _otherUid = if ((_message get "from") isEqualTo _uid) then { _message get "to" } else { _message get "from" };

                    if (!(_threadMap in _otherUid)) then {
                        _threadMap set [_otherUid, []];
                    };

                    private _thread = _threadMap get _otherUid;
                    _thread pushBack _message;
                    _threadMap set [_otherUid, _thread];
                } forEach _messageData;

                GVAR(MessageRegistry) set [_uid, _threadMap];
            };

            diag_log format ["[FORGE:Server:Phone:Message] Loaded messages for %1 into registry", _uid];
            true
        } catch {
            diag_log format ["[FORGE:Server:Phone:Message] Error loading messages from database for %1: %2", _uid, _exception];
            false
        };
    }],
    ["sendMessage", {
        params [["_fromUid", "", [""]], ["_toUid", "", [""]], ["_message", "", [""]]];

        if (_fromUid isEqualTo "" || _toUid isEqualTo "" || _message isEqualTo "") exitWith {
            diag_log "[FORGE:Server:Phone:Message] Invalid parameters provided to sendMessage";
            false
        };

        private _timestamp = serverTime;
        private _messageId = format ["%1_%2_%3", _fromUid, _toUid, _timestamp];

        // Create message object
        private _messageObj = createHashMapFromArray [
            ["id", _messageId],
            ["from", _fromUid],
            ["to", _toUid],
            ["message", _message],
            ["timestamp", _timestamp],
            ["read", false]
        ];

        // Add to sender's message registry
        private _senderThreads = GVAR(MessageRegistry) getOrDefault [_fromUid, createHashMap];
        if (!(_senderThreads in _toUid)) then { _senderThreads set [_toUid, []]; };

        private _senderThread = _senderThreads get _toUid;
        _senderThread pushBack _messageObj;
        _senderThreads set [_toUid, _senderThread];

        GVAR(MessageRegistry) set [_fromUid, _senderThreads];

        // Add to receiver's message registry
        private _receiverThreads = GVAR(MessageRegistry) getOrDefault [_toUid, createHashMap];
        if (!(_receiverThreads in _fromUid)) then { _receiverThreads set [_fromUid, []]; };

        private _receiverThread = _receiverThreads get _fromUid;
        _receiverThread pushBack _messageObj;
        _receiverThreads set [_fromUid, _receiverThread];

        GVAR(MessageRegistry) set [_toUid, _receiverThreads];

        // Store in database for both users
        try {
            private _messageArray = _self call ["toArray", [_messageObj]];
            [format ["%1:messages", _fromUid], [_messageArray]] call dragonfly_db_fnc_rpush;
            [format ["%1:messages", _toUid], [_messageArray]] call dragonfly_db_fnc_rpush;

            // Background sync to update indices
            _self call ["syncMessageIndices", [_fromUid]];
            _self call ["syncMessageIndices", [_toUid]];
        } catch {
            diag_log format ["[FORGE:Server:Phone:Message] Error saving message to database: %1", _exception];
        };

        // TODO: Notify both players

        diag_log format ["[FORGE:Server:Phone:Message] Message sent from %1 to %2: %3", _fromUid, _toUid, _message];
        true
    }],
    ["getMessageThread", {
        params [["_uid", "", [""]], ["_otherUid", "", [""]]];

        if (_uid isEqualTo "" || _otherUid isEqualTo "") exitWith {
            diag_log "[FORGE:Server:Phone:Message] Invalid parameters provided to getMessageThread";
            []
        };

        private _userThreads = GVAR(MessageRegistry) getOrDefault [_uid, createHashMap];
        private _thread = _userThreads getOrDefault [_otherUid, []];

        diag_log format ["[FORGE:Server:Phone:Message] Retrieved thread between %1 and %2 with %3 messages", _uid, _otherUid, count _thread];
        _thread
    }],
    ["markMessageRead", {
        params [["_uid", "", [""]], ["_messageId", "", [""]]];

        if (_uid isEqualTo "" || _messageId isEqualTo "") exitWith {
            diag_log "[FORGE:Server:Phone:Message] Invalid parameters provided to markMessageRead";
            false
        };

        private _userThreads = GVAR(MessageRegistry) getOrDefault [_uid, createHashMap];
        private _found = false;

        // Find the message in all threads and mark it as read
        {
            private _otherUid = _x;
            private _thread = _userThreads get _otherUid;

            {
                private _message = _x;
                if ((_message get "id") isEqualTo _messageId) then {
                    _message set ["read", true];
                    _found = true;
                };
            } forEach _thread;

        } forEach (keys _userThreads);

        if (_found) then {
            diag_log format ["[FORGE:Server:Phone:Message] Marked message %1 as read for %2", _messageId, _uid];
        } else {
            diag_log format ["[FORGE:Server:Phone:Message] Message %1 not found for %2", _messageId, _uid];
        };

        _found
    }],
    ["getMessages", {
        params [["_uid", "", [""]]];

        if (_uid isEqualTo "") exitWith {
            diag_log "[FORGE:Server:Phone:Message] Empty UID provided to getMessages";
            []
        };

        private _userThreads = GVAR(MessageRegistry) getOrDefault [_uid, createHashMap];
        private _allMessages = [];

        // Flatten all threads into a single array
        {
            private _thread = _userThreads get _x;
            _allMessages append _thread;
        } forEach (keys _userThreads);

        // Sort by timestamp
        _allMessages sort true;

        diag_log format ["[FORGE:Server:Phone:Message] Retrieved %1 messages for %2", count _allMessages, _uid];
        _allMessages
    }],
    ["remove", {
        params [["_uid", "", [""]]];

        if (_uid isEqualTo "") exitWith {
            diag_log "[FORGE:Server:Phone:Message] Empty UID provided to remove";
            false
        };

        // Remove from message registry
        GVAR(MessageRegistry) deleteAt _uid;

        diag_log format ["[FORGE:Server:Phone:Message] Removed message data for %1", _uid];
        true
    }],
    ["syncMessageIndices", {
        params [["_uid", "", [""]]];

        if (_uid isEqualTo "") exitWith {
            diag_log "[FORGE:Server:Phone:Message] Empty UID provided to syncMessageIndices";
            false
        };

        try {
            // Re-fetch all messages from database to get correct indices
            private _messageData = [format ["%1:messages", _uid]] call dragonfly_db_fnc_lrange;

            if (!isNil "_messageData" && { count _messageData > 0 }) then {
                private _userThreads = GVAR(MessageRegistry) getOrDefault [_uid, createHashMap];

                // Update all messages in registry with database indices
                {
                    private _message = _self call ["toHashMap", [_x]];
                    private _messageId = _message get "id";
                    private _dbIndex = _forEachIndex;

                    // Find and update this message in the registry
                    {
                        private _otherUid = _x;
                        private _thread = _userThreads get _otherUid;

                        {
                            private _registryMessage = _x;
                            if ((_registryMessage get "id") isEqualTo _messageId) then {
                                _registryMessage set ["index", _dbIndex];
                            };
                        } forEach _thread;

                    } forEach (keys _userThreads);

                } forEach _messageData;

                GVAR(MessageRegistry) set [_uid, _userThreads];
                diag_log format ["[FORGE:Server:Phone:Message] Synced message indices for %1", _uid];
            };

            true
        } catch {
            diag_log format ["[FORGE:Server:Phone:Message] Error syncing message indices for %1: %2", _uid, _exception];
            false
        };
    }],
    ["toArray", {
        params [["_data", createHashMap, [createHashMap]]];

        private _keys = keys _data;
        private _array = [];

        {
            private _key = _x;
            private _value = _data get _key;
            _array pushBack _key;
            _array pushBack _value;
        } forEach _keys;

        _array
    }],
    ["toHashMap", {
        params [["_data", [], [[]]]];

        private _keyValuePairs = [];
        _data = _data select 0;

        for "_i" from 0 to (count _data - 2) step 2 do {
            private _key = _data select _i;
            private _value = _data select (_i + 1);
            _keyValuePairs set [_key, _value];
        };

        private _hashMap = createHashMapFromArray _keyValuePairs;
        _hashMap
    }]
]];

SETMVAR(FORGE_MessageStore,GVAR(MessageStore));
GVAR(MessageStore)
