const vge_app = angular.module('vge_app.module', []);


vge_app.factory('PythonService', ['$q', function ($q) {
    let _registeredCallPythonDo = null;

    return {
        registerCallPythonDoFunction: function (fn) {
            if (typeof fn === 'function') {
                _registeredCallPythonDo = fn;
                console.log("PythonService: callPythonDo function registered.");
            } else {
                console.error("PythonService: Attempted to register an invalid callPythonDo function.");
                _registeredCallPythonDo = null; // Ensure it's null if registration fails
            }
        },

        unregisterCallPythonDoFunction: function () {
            _registeredCallPythonDo = null;
            console.log("PythonService: callPythonDo function unregistered.");
        },

        callPythonDo: function (params) {
            if (typeof _registeredCallPythonDo === 'function') {
                try {
                    // Directly call the registered function.
                    // If it needs a specific 'this', it should have been bound
                    // before being passed to registerCallPythonDoFunction.
                    return _registeredCallPythonDo(params);
                } catch (e) {
                    console.error("PythonService: Error calling registered function:", e);
                    return $q.reject("Error in registered callPythonDo: " + e.message);
                }
            } else {
                console.error("PythonService: callPythonDo function not registered. Cannot proceed.");
                return $q.reject("callPythonDo function not registered in PythonService");
            }
        }
    };
}]);

// Define the module with a unique name to avoid conflicts
vge_app.controller('vgeController', ['$scope', '$timeout', 'PythonService', 'DataikuAPI', '$q', function ($scope, $timeout, PythonService, DataikuAPI, $q, $http) {

    $scope.config = $scope.config || {}; //expose au parent de selector controller

    if (typeof $scope.callPythonDo === 'function') {
        PythonService.registerCallPythonDoFunction($scope.callPythonDo);
    } else {
        console.error("selectorController: $scope.callPythonDo is NOT a function at the time of registration attempt. PythonService calls will fail.");
        // Fallback to a dummy to avoid breaking PythonService if it's called before a proper registration
        PythonService.registerCallPythonDoFunction(function () {
            console.error("Attempted to use PythonService with an uninitialized callPythonDo from selectorController");
            return $q.reject("callPythonDo was not properly initialized in selectorController for PythonService.");
        });
    }
}])

vge_app.directive('inputWithLabel', function () {
    return {
        restrict: 'E',
        templateUrl: '/plugins/visual-graph/resource/custom-ui-settings/input-with-label.html',
        scope: {
            config: '=',
            labelText: '@',
            configProperty: '@',
            initialWidth: '@?',
            initialHeight: '@?',
            placeholder: '@?',
            description: '@',
            fieldRequired: '@?',
            formName: '=',
            customMargin: '@?'
        },
        link: function (scope, element, attrs) {
            // Set default dimensions if not provided
            scope.initialWidth = scope.initialWidth || '100%';
            scope.initialHeight = scope.initialHeight || '80px';
            scope.required = scope.required || false;
            // Convert string required to boolean
            scope.isRequired = scope.fieldRequired === 'true';

            var textarea = element.find('textarea')[0];

            if (textarea) {
                textarea.style.width = scope.initialWidth;
                textarea.style.height = scope.initialHeight;
            }

        },
        controller: ['$scope', '$timeout', function ($scope, $timeout) {
            if (!$scope.config[$scope.configProperty]) {
                $scope.config[$scope.configProperty] = "";
            }

            // Watch for changes to detect if something sets it to undefined
            //While debugging, we noticed that the property was set to undefined
            // This is dangerous because we need the value to be present in the config object (if it set to undefined, the serialization of the config object dont save the configproperty )
            $scope.$watch('config.' + $scope.configProperty, function (newVal) {
                if (newVal === undefined) {
                    console.log('Property was set to undefined, resetting to empty string');
                    $scope.config[$scope.configProperty] = "";
                }
            });

            $scope.isFieldEmpty = function () {
                // Check if the field is undefined, null, or an empty string
                return $scope.config[$scope.configProperty] === undefined || $scope.config[$scope.configProperty] === null || $scope.config[$scope.configProperty].trim() === "";
            };

        }]

    };
});

vge_app.directive('selector', ['PythonService', function (PythonService) {
    return {
        restrict: 'E',
        templateUrl: '/plugins/visual-graph/resource/custom-ui-settings/selector-template.html',
        scope: {    
            config: '=',
            formName: '=',
            labelText: '@',
            fieldRequired: '@?',
            configProperty: '@',
            description: '@',
            emptySelectorMessage: '@?'
        },
        link: function (scope){
            scope.config = scope.config || {}; // Ensure config exists
            scope.isRequired = scope.fieldRequired === 'true';
        },
        controller: ['$scope', '$timeout', '$element', function ($scope, $timeout, $element) { // Added $element
            $scope.isDropDown = false;
            $scope.choiceFilter = ''; // Model for the main input field
            $scope.choices = [];
            $scope.selectedChoice = null;

            $scope.isChoiceFocused = false; // For ng-class styling
            var blurTimeout = null;   // For managing blur event

           
            function processChoices(choices) {
                if (!choices || !Array.isArray(choices)) return [];
                // Filter out the "None" option (empty string value or label "None")
                return choices.filter(function (choice) {
                    return choice.value !== "" && choice.label.toLowerCase() !== "none";
                });

            }

            function initializeSelectedChoice() {
                if ($scope.config[$scope.configProperty]) {
                    var property = $scope.config[$scope.configProperty];
                    var foundSnapshot = $scope.choices.find(f => f.value === property);
                    if (foundSnapshot) {
                        $scope.selectedChoice = foundSnapshot;
                        $scope.choiceFilter = foundSnapshot.label; // Set input text
                    }
                    else{
                        $scope.config[$scope.configProperty] = null;
                        $scope.selectedChoice = null;
                        $scope.choiceFilter = '';
                    }
                } else {
                    $scope.config[$scope.configProperty] = null;
                    $scope.selectedChoice = null;
                    $scope.choiceFilter = '';
                }
            }

            $scope.initSnapshotData = function () {               
                PythonService.callPythonDo({parameterName: $scope.configProperty})
                    .then(function (data) {
                        if (data && data.choices) {
                            $scope.choices = processChoices(data.choices);
                        } else {
                            console.error('Invalid choices data format:', data);
                            $scope.choices = processChoices([]);
                        }
                        initializeSelectedChoice();
                    }, function (error) {
                        console.error('Failed to fetch choices:', error);
                        $scope.choices = processChoices([]);
                        initializeSelectedChoice();
                    });
            };

            var documentClickHandler = function (event) {
                const inputWrapper = $element[0].querySelector('div[ng-class*="isChoiceFocused"]'); // A more unique identifier for that div

                if ($scope.isDropDown && inputWrapper && !inputWrapper.contains(event.target)) {
                    // Also ensure the click is not on the dropdown itself if it's rendered outside this wrapper
                    const dropdownElement = $element[0].querySelector('div[ng-if="isDropDown"]');
                    if (dropdownElement && dropdownElement.contains(event.target)) {
                        return; // Click was inside the dropdown menu
                    }
                    $scope.$apply(function () {
                        $scope.closeDropdownAndRevertText();
                    });
                }
            };
            $scope.closeDropdownAndRevertText = function () {
                $scope.isDropDown = false;
                $scope.isChoiceFocused = false;
                angular.element(document).off('click', documentClickHandler);
                if ($scope.selectedChoice) {
                    $scope.choiceFilter = $scope.selectedChoice.label;
                } else {
                    // $scope.choiceFilter = ''; 
                }
            };

            $scope.openDropdown = function ($event) {
                if ($event) $event.stopPropagation();
                if (blurTimeout) $timeout.cancel(blurTimeout);

                if (!$scope.isDropDown) {
                    $scope.isDropDown = true;
                    $timeout(function () {
                        angular.element(document).on('click', documentClickHandler);
                    }, 0);
                }
            };

            $scope.selectChoice = function (choice) {
                if (blurTimeout) $timeout.cancel(blurTimeout);
                $scope.selectedChoice = choice;
                $scope.config[$scope.configProperty] = choice.value;
                $scope.choiceFilter = choice.label;
                $scope.isDropDown = false;
                $scope.isChoiceFocused = false;
                angular.element(document).off('click', documentClickHandler);
            };

            $scope.clearSelection = function () { // Renamed from clearchoiceFilter
                $scope.choiceFilter = '';
                $scope.selectedChoice = null;
                $scope.config[$scope.configProperty] = null; // Clear stored value
                // Optionally re-open or focus:
                $scope.openDropdown();
                $element[0].querySelector('input').focus();
            };

            $scope.handleInputChange = function () {
                if ($scope.selectedChoice && $scope.choiceFilter !== $scope.selectedChoice.label) {
                    $scope.selectedChoice = null;
                    $scope.config[$scope.configProperty] = null; // Clear if text changed from selection
                }
                if (!$scope.isDropDown && $scope.choiceFilter) {
                    $scope.openDropdown();
                }
            };

            $scope.handleInputBlur = function () {
                blurTimeout = $timeout(function () {
                    if ($scope.isDropDown) {
                        $scope.closeDropdownAndRevertText();
                    }
                }, 200);
            };

            // Filter function for the choices (used by ng-repeat | filter:choiceFilterFn)
            $scope.choiceFilterFn = function (choice) {
                if (choice && typeof choice.label === 'string') { // Add check for choice and label
                    if (!$scope.choiceFilter) {
                        return true; // Show all if no filter text
                    }
                    const filterText = $scope.choiceFilter.toLowerCase();
                    return choice.label.toLowerCase().includes(filterText);
                }
                return false; // Don't show if choice or label is invalid
            };

            $scope.$on('$destroy', function () {
                angular.element(document).off('click', documentClickHandler);
                if (blurTimeout) $timeout.cancel(blurTimeout);
            });

            $scope.initSnapshotData();
        }]
    };
}]);
