#include "..\script_component.hpp"

/*
 * File: fnc_initActorStore.sqf
 * Author: IDSolutions
 * Date: 2025-12-17
 * Last Update: 2026-01-30
 * Public: Yes
 *
 * Description:
 * Initializes the actor store for managing player actor data.
 * Provides methods for creating, fetching, migrating, and validating actor data.
 *
 * Arguments:
 * None
 *
 * Return Value:
 * Actor store object [HASHMAP OBJECT]
 *
 * Example:
 * call forge_server_actor_fnc_initActorStore
 */

#pragma hemtt ignore_variables ["_self"]
GVAR(ActorModel) = compileFinal createHashMapObject [[
    ["#type", "ActorModel"],
    ["defaults", {
        private _actor = createHashMap;

        _actor set ["uid", ""];
        _actor set ["name", ""];
        _actor set ["loadout", [[],[],[],["U_BG_Guerrilla_6_1",[["FirstAidKit", 2]]],[],[],"H_Cap_blk_ION","",[],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]];
        _actor set ["position", [0,0,0]];
        _actor set ["direction", 0];
        _actor set ["stance", "STAND"];
        _actor set ["rank", "PRIVATE"];
        _actor set ["state", "HEALTHY"];
        _actor set ["phone_number", ""];
        _actor set ["email", ""];
        _actor set ["organization", ""];
        _actor set ["holster", true];

        _actor
    }],
    ["fromPlayer", {
        params [["_player", objNull, [objNull]]];

        if (_player isEqualTo objNull) exitWith { _self call ["defaults", []] };

        private _actor = _self call ["defaults", []];

        _actor set ["uid", getPlayerUID _player];
        _actor set ["name", name _player];
        _actor set ["position", getPosASL _player];
        _actor set ["direction", getDir _player];
        _actor set ["stance", stance _player];
        _actor set ["rank", rank _player];
        _actor set ["state", lifeState _player];

        _actor
    }],
    ["migrate", {
        params [["_actor", createHashMap, [createHashMap]]];

        private _defaults = _self call ["defaults", []];

        {
            if !(_x in _actor) then { _actor set [_x, _y]; };
        } forEach _defaults;

        _actor
    }],
    ["validate", {
        params [["_actor", createHashMap, [createHashMap]]];

        private _uid = _actor getOrDefault ["uid", ""];
        private _name = _actor getOrDefault ["name", ""];
        private _position = _actor getOrDefault ["position", []];
        private _direction = _actor getOrDefault ["direction", 0];
        private _stance = _actor getOrDefault ["stance", ""];
        private _rank = _actor getOrDefault ["rank", ""];
        private _state = _actor getOrDefault ["state", ""];
        private _phone_number = _actor getOrDefault ["phone_number", ""];
        private _email = _actor getOrDefault ["email", ""];
        private _organization = _actor getOrDefault ["organization", ""];

        [_uid, _name, _position, _direction, _stance, _rank, _state, _phone_number, _email, _organization] try {
            if (_uid isEqualTo "" || !(_uid isEqualType "")) then { throw "Invalid UID!"; };
            if (_name isEqualTo "" || !(_name isEqualType "")) then { throw "Invalid Name!"; };
            if (_position isEqualTo [] || !(_position isEqualType [])) then { throw "Invalid Position!"; };
            if (_direction < 0 || !(_direction isEqualType 0)) then { throw "Invalid Direction!"; };
            if (_stance isEqualTo "" || !(_stance isEqualType "")) then { throw "Invalid Stance!"; };
            if (_rank isEqualTo "" || !(_rank isEqualType "")) then { throw "Invalid Rank!"; };
            if (_state isEqualTo "" || !(_state isEqualType "")) then { throw "Invalid State!"; };
            if (_phone_number isEqualTo "" || !(_phone_number isEqualType "")) then { throw "Invalid Phone Number!"; };
            if (_email isEqualTo "" || !(_email isEqualType "")) then { throw "Invalid Email!"; };
            if (_organization isEqualTo "" || !(_organization isEqualType "")) then { throw "Invalid Organization!"; };
        } catch {
            ["ERROR", format ["Failed to validate actor %1!", _exception]] call EFUNC(common,log);
            false
        };

        true
    }]
]];

GVAR(ActorRepository) = compileFinal createHashMapFromArray [
    ["#base", EGVAR(common,BaseStore)],
    ["#type", "ActorRepository"],
    ["#create", {
        GVAR(ActorRegistry) = createHashMap;
        ["INFO", "Actor Repository Initialized!"] call EFUNC(common,log);
    }],
    ["get", {
        params [["_uid", "", [""]]];

        private _cached = GVAR(ActorRegistry) getOrDefault [_uid, nil];
        if !(isNil { _cached }) exitWith { _cached };

        private _player = [_uid] call EFUNC(common,getPlayer);

        ["actor:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
        if !(_isSuccess) exitWith {
            ["ERROR", format ["Failed to check if actor %1 exists!", _uid]] call EFUNC(common,log);
            createHashMap
        };

        private _finalActor = createHashMap;

        if (_result == "true") then {
            _finalActor = _self call ["fetch", ["actor:get", _uid]];
            ["INFO", format ["Found actor for %1", _uid]] call EFUNC(common,log);
        } else {
            _finalActor = GVAR(ActorModel) call ["fromPlayer", [_player]];
            _finalActor set ["uid", _uid];

            private _json = _self call ["toJSON", [_finalActor]];
            ["actor:create", [_uid, _json]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
            if !(_isSuccess) exitWith {
                ["ERROR", format ["Failed to create actor %1!", _uid]] call EFUNC(common,log);
                createHashMap
            };

            ["INFO", format ["Created new actor for %1", _uid]] call EFUNC(common,log);
        };

        _finalActor = GVAR(ActorModel) call ["migrate", [_finalActor]];
        GVAR(ActorRegistry) set [_uid, _finalActor];
        _finalActor

    }]
];

GVAR(ActorStore) = createHashMapObject [[
    ["#base", GVAR(ActorRepository)],
    ["#type", "IActorStore"],
    ["#create", {
        ["INFO", "Actor Store Initialized!"] call EFUNC(common,log);
    }],
    ["init", {
        params [["_uid", "", [""]]];

        private _actor = _self call ["get", [_uid]];
        private _player = [_uid] call EFUNC(common,getPlayer);

        [CRPC(actor,responseInitActor), [_actor], _player] call CFUNC(targetEvent);
        _actor
    }]
]];

GVAR(ActorStore)
