// src/core/state.js

const globalState = new Map();

/**
 * Normale State-Erstellung (nicht persistent)
 */
export function createState(key, initialValue) {
    if (!globalState.has(key)) globalState.set(key, initialValue);

    return {
        get() {
            return globalState.get(key);
        },
        set(value) {
            globalState.set(key, value);
            dispatchEvent(new CustomEvent('statechange', {
                detail: { key, value }
            }));
        },
        subscribe(callback) {
            const handler = (event) => {
                if (event.detail.key === key) {
                    callback(event.detail.value);
                }
            };
            addEventListener('statechange', handler);
            return () => removeEventListener('statechange', handler);
        }
    };
}

/**
 * Persistent State via localStorage
 */
export function createPersistentState(key, defaultValue) {
    const stored = localStorage.getItem(`state:${key}`);
    const initial = stored !== null ? JSON.parse(stored) : defaultValue;

    const state = createState(key, initial);

    state.subscribe((val) => {
        localStorage.setItem(`state:${key}`, JSON.stringify(val));
    });

    return state;
}

/**
 * Zugriff auf alle States (intern)
 */
export function getRawState() {
    return globalState;
}

/**
 * Elementbindung: Text, Attribut, Klasse oder Custom-Callback
 */
export function bindStateToElement({ state, element, property = 'text', attributeName = null }) {
    const apply = (value) => {
        if (property === 'text') {
            element.textContent = value;
        } else if (property === 'attr' && attributeName) {
            element.setAttribute(attributeName, value);
        } else if (property === 'class') {
            element.className = value;
        } else if (typeof property === 'function') {
            property(element, value);
        }
    };

    apply(state.get());
    return state.subscribe(apply);
}

/**
 * Mehrere Elemente gleichzeitig binden
 */
export function bindStateToElements({ state, elements, ...rest }) {
    return elements.map(el => bindStateToElement({ state, element: el, ...rest }));
}

/**
 * Declarative Auto-Bindings via data-bind Attribute
 */
export function initStateBindings() {
    document.querySelectorAll('[data-bind]').forEach(el => {
        const key = el.getAttribute('data-bind');
        const state = createState(key, '');
        bindStateToElement({ state, element: el, property: 'text' });
    });

    document.querySelectorAll('[data-bind-attr]').forEach(el => {
        const key = el.getAttribute('data-bind-attr');
        const attr = el.getAttribute('data-bind-attr-name') || 'value';
        const state = createState(key, '');
        bindStateToElement({ state, element: el, property: 'attr', attributeName: attr });
    });

    document.querySelectorAll('[data-bind-class]').forEach(el => {
        const key = el.getAttribute('data-bind-class');
        const state = createState(key, '');
        bindStateToElement({ state, element: el, property: 'class' });
    });

    document.querySelectorAll('[data-bind-input]').forEach(el => {
        const key = el.getAttribute('data-bind-input');
        const persistent = el.hasAttribute('data-persistent');
        const state = persistent ? createPersistentState(key, '') : createState(key, '');

        bindInputToState(el, state);
    });
}

/**
 * Zwei-Wege-Bindung für Formulareingaben
 */
export function bindInputToState(inputEl, state) {
    // Initialwert setzen
    if (inputEl.type === 'checkbox') {
        inputEl.checked = !!state.get();
    } else {
        inputEl.value = state.get();
    }

    // DOM → State
    inputEl.addEventListener('input', () => {
        if (inputEl.type === 'checkbox') {
            state.set(inputEl.checked);
        } else {
            state.set(inputEl.value);
        }
    });

    // State → DOM
    return state.subscribe((val) => {
        if (inputEl.type === 'checkbox') {
            inputEl.checked = !!val;
        } else {
            inputEl.value = val;
        }
    });
}


/**
 * Berechneter Zustand auf Basis anderer States
 */
export function createComputedState(dependencies, computeFn) {
    let value = computeFn(...dependencies.map(d => d.get()));
    const key = `computed:${Math.random().toString(36).slice(2)}`;
    const state = createState(key, value);

    dependencies.forEach(dep => {
        dep.subscribe(() => {
            const newValue = computeFn(...dependencies.map(d => d.get()));
            state.set(newValue);
        });
    });

    return state;
}

/**
 * Aktiviert Undo/Redo für einen State
 */
export function enableUndoRedoForState(state) {
    const history = [];
    let index = -1;
    let lock = false;

    const record = (val) => {
        if (lock) return;
        history.splice(index + 1); // zukünftige States verwerfen
        history.push(val);
        index++;
    };

    record(state.get());

    const unsubscribe = state.subscribe((val) => {
        if (!lock) record(val);
    });

    return {
        undo() {
            if (index > 0) {
                lock = true;
                index--;
                state.set(history[index]);
                lock = false;
            }
        },
        redo() {
            if (index < history.length - 1) {
                lock = true;
                index++;
                state.set(history[index]);
                lock = false;
            }
        },
        destroy: unsubscribe
    };
}

/**
 * Dev-Konsole zur Nachverfolgung von State-Änderungen
 */
export function enableStateLogging(state, label = 'state') {
    state.subscribe((val) => {
        console.debug(`[State Change: ${label}]`, val);
    });
}
