class_name PRDConfigManager
extends RefCounted

## Менеджер конфигурации для системы контроля ПРД.
## Загружает и управляет настройками из JSON-конфигурации.

#region CONSTANTS
const CONFIG_PATH = 'user://config/setting_prd_control.json'
const DEFAULT_CONFIG_PATH = 'res://config/setting_prd_control.json'
const CONFIG_VERSION = '1.0.0'  # Версия конфигурации - увеличивать при изменениях
#endregion

#region PRIVATE_VARIABLES
var _config_data: Dictionary                ## Все данные конфигурации
var _device_constants: Dictionary           ## Константы устройств
var _base_configs: Dictionary               ## Базовые конфигурации
var _device_configs: Dictionary             ## Конфигурации устройств
var _data_indices: Dictionary               ## Индексы данных
var _fs_keys: Dictionary                    ## Ключи ФС (функциональных систем)
var _temperature_constants: Dictionary      ## Константы температуры
var _ems_input_bits_config: Dictionary      ## Конфигурация битов ввода ЭМС
var _fs_rules: Array                        ## Правила ФС

var _is_loaded: bool = false                ## Флаг успешной загрузки
var _current_version: String                ## Текущая версия загруженной конфигурации
#endregion

#region INITIALIZATION
func _init() -> void:
    """Инициализация менеджера конфигурации"""
    _load_configuration()
#endregion

#region PUBLIC_API
## Проверяет, успешно ли загружена конфигурация
func is_loaded() -> bool:
    return _is_loaded

## Возвращает текущую версию загруженной конфигурации
func get_config_version() -> String:
    return _current_version

## Проверяет, актуальна ли конфигурация
func is_config_up_to_date() -> bool:
    return _current_version == CONFIG_VERSION

## Возвращает все данные конфигурации
func get_config_data() -> Dictionary:
    return _config_data.duplicate(true)

## Возвращает константы устройств
func get_device_constants() -> Dictionary:
    return _device_constants.duplicate(true)

## Возвращает базовые конфигурации
func get_base_configs() -> Dictionary:
    return _base_configs.duplicate(true)

## Возвращает конфигурации устройств
func get_device_configs() -> Dictionary:
    return _device_configs.duplicate(true)

## Возвращает индексы данных
func get_data_indices() -> Dictionary:
    return _data_indices.duplicate(true)

## Возвращает ключи ФС
func get_fs_keys() -> Dictionary:
    return _fs_keys.duplicate(true)

## Возвращает константы температуры
func get_temperature_constants() -> Dictionary:
    return _temperature_constants.duplicate(true)

## Возвращает конфигурацию битов ввода ЭМС
func get_ems_input_bits_config() -> Dictionary:
    return _ems_input_bits_config.duplicate(true)

## Возвращает правила ФС
func get_fs_rules() -> Array:
    return _fs_rules.duplicate(true)

## Возвращает индекс данных по ключу
func get_data_index(key: String) -> int:
    return _data_indices.get(key, -1)
#endregion

#region PRIVATE_METHODS
## Загружает конфигурацию из JSON файла
func _load_configuration() -> void:
    if not _ensure_config_exists():
        _is_loaded = false
        return

    var config_file = FileAccess.open(CONFIG_PATH, FileAccess.READ)
    if config_file:
        var json_text = config_file.get_as_text()
        config_file.close()

        var json = JSON.new()
        var parse_result = json.parse(json_text)
        if parse_result == OK:
            _config_data = json.data
            _current_version = _config_data.get('config_version', '0.0.0')
            _parse_config_data()
            _is_loaded = true
        else:
            push_error('Ошибка разбора JSON конфигурации: ' + json.get_error_message())
            _is_loaded = false
    else:
        push_error('Ошибка загрузки файла конфигурации: ' + CONFIG_PATH)
        _is_loaded = false


## Парсит данные конфигурации по секциям
func _parse_config_data() -> void:
    _device_constants = _convert_numbers(_config_data.get('device_constants', {}))
    _base_configs = _convert_numbers(_config_data.get('base_configs', {}))
    _device_configs = _convert_numbers(_config_data.get('device_configs', {}))
    _data_indices = _convert_numbers(_config_data.get('data_indices', {}))
    _fs_keys = _convert_numbers(_config_data.get('fs_keys', {}))
    _temperature_constants = _convert_numbers(_config_data.get('temperature_constants', {}))
    _ems_input_bits_config = _convert_numbers(_config_data.get('ems_input_bits_config', {}))
    _fs_rules = _convert_numbers(_config_data.get('fs_rules', []))


## Конвертирует числовые значения в правильные типы (float -> int если возможно)
static func _convert_numbers(value):
    if value is float:
        # Конвертируем float в int если нет дробной части
        if value == int(value):
            return int(value)
        return value
    elif value is Dictionary:
        var result = {}
        for key in value:
            result[key] = _convert_numbers(value[key])
        return result
    elif value is Array:
        var result = []
        for item in value:
            result.append(_convert_numbers(item))
        return result
    else:
        return value


## Обеспечивает существование файла конфигурации
## Создает папку и копирует дефолтный файл если нужно
func _ensure_config_exists() -> bool:
    # Создаем папку конфигурации если не существует
    DirAccess.make_dir_recursive_absolute('user://config')

    # Проверяем, нужно ли обновить конфигурацию
    if _should_update_config():
        return _update_config()

    # Если файл уже существует - все ок
    if FileAccess.file_exists(CONFIG_PATH):
        return true

    # Если дефолтного файла нет - ошибка
    if not FileAccess.file_exists(DEFAULT_CONFIG_PATH):
        return false

    # Копируем дефолтный конфиг в user директорию
    return _copy_default_config()


## Проверяет, нужно ли обновить конфигурацию
func _should_update_config() -> bool:
    # Если файла конфигурации нет - нужно создать
    if not FileAccess.file_exists(CONFIG_PATH):
        return true

    # Проверяем версию существующей конфигурации
    var config_file = FileAccess.open(CONFIG_PATH, FileAccess.READ)
    if config_file:
        var json_text = config_file.get_as_text()
        config_file.close()

        var json = JSON.new()
        if json.parse(json_text) == OK:
            var existing_version = json.data.get('config_version', '0.0.0')
            # Сравниваем версии
            return _compare_versions(existing_version, CONFIG_VERSION) < 0
        else:
            # Если ошибка парсинга - нужно обновить
            return true

    return false


## Сравнивает две версии (semantic versioning)
## Возвращает -1 если version1 < version2, 0 если равны, 1 если version1 > version2
static func _compare_versions(version1: String, version2: String) -> int:
    var v1_parts = version1.split('.')
    var v2_parts = version2.split('.')

    for i in range(max(v1_parts.size(), v2_parts.size())):
        var v1_part = int(v1_parts[i]) if i < v1_parts.size() else 0
        var v2_part = int(v2_parts[i]) if i < v2_parts.size() else 0

        if v1_part < v2_part:
            return -1
        elif v1_part > v2_part:
            return 1

    return 0


## Обновляет конфигурацию до актуальной версии
func _update_config() -> bool:
    # Создаем резервную копию старой конфигурации
    if FileAccess.file_exists(CONFIG_PATH):
        var backup_path = CONFIG_PATH + '.backup_v' + _current_version
        DirAccess.copy_absolute(CONFIG_PATH, backup_path)

    # Копируем актуальную конфигурацию
    return _copy_default_config()


## Копирует дефолтную конфигурацию в user директорию
func _copy_default_config() -> bool:
    if not FileAccess.file_exists(DEFAULT_CONFIG_PATH):
        push_error('Файл конфигурации не найден: ' + DEFAULT_CONFIG_PATH)
        return false

    var src := FileAccess.open(DEFAULT_CONFIG_PATH, FileAccess.READ)
    var dst := FileAccess.open(CONFIG_PATH, FileAccess.WRITE)
    if src == null or dst == null:
        push_error('Ошибка копирования конфигурации')
        return false

    dst.store_string(src.get_as_text())
    src.close()
    dst.close()
    return true
#endregion
