import { defineStore } from 'pinia';
import { ref, computed, reactive } from 'vue';
import { normalizeScreen, normalizeWidget } from '../utils';
import { MAX_SCREENS, WIDGET_DEFAULTS, WIDGET_TYPES, TEXT_ALIGNS } from '../constants';

export const useEditorStore = defineStore('editor', () => {
    const config = reactive({
        startScreen: 0,
        standby: { enabled: false, screen: -1, minutes: 5 },
        screens: []
    });

    const knxAddresses = ref([]);
    const selectedWidgetId = ref(null);
    const activeScreenId = ref(0);
    const canvasScale = ref(0.6);
    const showGrid = ref(true);
    const snapToGrid = ref(true);
    const gridSize = ref(20);
    const powerLinkMode = reactive({ active: false, powerflowId: null, fromNodeId: null });

    const nextScreenId = ref(0);
    const nextWidgetId = ref(0);

    const activeScreen = computed(() => {
        return config.screens.find(s => s.id === activeScreenId.value) || config.screens[0];
    });

    const widgetTree = computed(() => {
        if (!activeScreen.value) return [];
        const widgets = activeScreen.value.widgets.filter(w => w.type !== WIDGET_TYPES.POWERLINK);
        
        // Map ID -> Widget
        const map = {};
        widgets.forEach(w => map[w.id] = { ...w, children: [] });
        
        const roots = [];
        widgets.forEach(w => {
            const node = map[w.id];
            if (w.parentId !== -1 && map[w.parentId]) {
                map[w.parentId].children.push(node);
            } else {
                roots.push(node);
            }
        });
        
        return roots;
    });

    const selectedWidget = computed(() => {
        if (!activeScreen.value || selectedWidgetId.value === null) return null;
        return activeScreen.value.widgets.find(w => w.id === selectedWidgetId.value);
    });

    function ensureButtonLabels(screen) {
        if (!screen || !Array.isArray(screen.widgets)) return;

        const hasLabelChild = new Set();
        screen.widgets.forEach((w) => {
            if (w.type === WIDGET_TYPES.LABEL && w.parentId !== -1) {
                hasLabelChild.add(w.parentId);
            }
        });

        screen.widgets.forEach((w) => {
            if (w.type !== WIDGET_TYPES.BUTTON) return;
            w.isContainer = true;

            if (hasLabelChild.has(w.id)) return;

            const defaults = WIDGET_DEFAULTS.label;
            const labelText = w.text || WIDGET_DEFAULTS.button.text;
            const label = {
                id: nextWidgetId.value++,
                parentId: w.id,
                type: WIDGET_TYPES.LABEL,
                x: 0,
                y: 0,
                w: w.w,
                h: w.h,
                visible: true,
                textSrc: defaults.textSrc,
                text: labelText,
                knxAddr: defaults.knxAddr,
                fontSize: w.fontSize ?? defaults.fontSize,
                textAlign: w.textAlign ?? TEXT_ALIGNS.CENTER,
                textColor: w.textColor ?? defaults.textColor,
                bgColor: defaults.bgColor,
                bgOpacity: 0,
                radius: 0,
                shadow: { ...defaults.shadow, enabled: false },
                isToggle: false,
                knxAddrWrite: 0,
                action: 0,
                targetScreen: 0,
                iconCodepoint: w.iconCodepoint || 0,
                iconPosition: w.iconPosition ?? defaults.iconPosition,
                iconSize: w.iconSize ?? defaults.iconSize,
                iconGap: w.iconGap ?? defaults.iconGap
            };

            screen.widgets.push(label);
            hasLabelChild.add(w.id);
        });
    }

    async function loadKnxAddresses() {
        try {
            // Mock or Real API
            const resp = await fetch('/api/knx/addresses');
            if (resp.ok) {
                knxAddresses.value = await resp.json();
            } else {
                knxAddresses.value = [];
            }
        } catch (e) {
            console.error(e);
            knxAddresses.value = [];
        }
    }

    async function loadConfig() {
        try {
            const resp = await fetch('/api/config');
            let data = {};
            if (resp.ok) {
                 data = await resp.json();
            } else {
                 // Fallback for dev without API
                 console.warn("API not available, loading defaults");
                 data = { screens: [] };
            }

            if (Array.isArray(data.screens)) {
                // reset reactive object properties
                Object.assign(config, data);
            } else {
                 // Default init
                 config.screens = [
                     {
                         id: 0,
                         name: 'Screen 1',
                         mode: 0,
                         bgColor: data.bgColor || '#1A1A2E',
                         widgets: data.widgets || []
                     }
                 ];
                 config.startScreen = 0;
                 config.standby = { enabled: false, screen: -1, minutes: 5 };
            }

            if (!config.standby) {
                config.standby = { enabled: false, screen: -1, minutes: 5 };
            }

            // Recalculate IDs
            nextWidgetId.value = 0;
            nextScreenId.value = 0;
            config.screens.forEach((screen) => {
                if (typeof screen.id === 'number') {
                    nextScreenId.value = Math.max(nextScreenId.value, screen.id + 1);
                }
            });

            config.screens.forEach((screen) => {
                normalizeScreen(screen, nextScreenId, nextWidgetId);
                ensureButtonLabels(screen);
                // Also update max widget id
                screen.widgets.forEach(w => {
                    nextWidgetId.value = Math.max(nextWidgetId.value, w.id + 1);
                });
            });

            // Validate start/standby screens
             if (config.standby.screen >= 255) config.standby.screen = -1;
             
             const startExists = config.screens.find(s => s.id === config.startScreen);
             if (!startExists && config.screens.length) {
                 config.startScreen = config.screens[0].id;
             }

             activeScreenId.value = config.screens.find(s => s.id === config.startScreen)?.id ?? 0;

        } catch (e) {
            console.error('Load config failed', e);
        }
    }

    async function saveConfig() {
        await fetch('/api/config', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(config)
        });
        await fetch('/api/save', { method: 'POST' });
    }

    async function resetConfig() {
        await fetch('/api/reset', { method: 'POST' });
        await loadConfig();
    }

    function addScreen() {
        if (config.screens.length >= MAX_SCREENS) return;
        const id = nextScreenId.value++;
        const newScreen = {
            id,
            name: `Screen ${id}`,
            mode: 0,
            bgColor: '#1A1A2E',
            widgets: []
        };
        normalizeScreen(newScreen, null, nextWidgetId);
        config.screens.push(newScreen);
        activeScreenId.value = id;
        selectedWidgetId.value = null;
    }

    function deleteScreen() {
        if (config.screens.length <= 1) return;
        
        config.screens = config.screens.filter(s => s.id !== activeScreenId.value);
        
        if (config.startScreen === activeScreenId.value) {
            config.startScreen = config.screens[0].id;
        }
        if (config.standby.screen === activeScreenId.value) {
            config.standby.screen = -1;
            config.standby.enabled = false;
        }
        
        activeScreenId.value = config.screens[0].id;
        selectedWidgetId.value = null;
    }

    function addWidget(typeStr) {
        if (!activeScreen.value) return;

        let typeValue;
        switch (typeStr) {
            case 'label': typeValue = WIDGET_TYPES.LABEL; break;
            case 'button': typeValue = WIDGET_TYPES.BUTTON; break;
            case 'led': typeValue = WIDGET_TYPES.LED; break;
            case 'icon': typeValue = WIDGET_TYPES.ICON; break;
            case 'tabview': typeValue = WIDGET_TYPES.TABVIEW; break;
            case 'tabpage': typeValue = WIDGET_TYPES.TABPAGE; break;
            case 'powerflow': typeValue = WIDGET_TYPES.POWERFLOW; break;
            case 'powernode': typeValue = WIDGET_TYPES.POWERNODE; break;
            case 'powerlink': typeValue = WIDGET_TYPES.POWERLINK; break;
            default: typeValue = WIDGET_TYPES.LABEL;
        }
        
        // Special case: Add Page to existing TabView
        if (typeStr === 'tabview' && selectedWidgetId.value !== null) {
            const sel = activeScreen.value.widgets.find(w => w.id === selectedWidgetId.value);
            if (sel && sel.type === WIDGET_TYPES.TABVIEW) {
                // User clicked "Tabs" while a TabView is selected -> Add a Page
                addWidget('tabpage');
                return;
            }
        }

        const defaults = WIDGET_DEFAULTS[typeStr];
        
        // Determine parent
        let parentId = -1;
        let startX = 120;
        let startY = 120;
        
        if (selectedWidgetId.value !== null) {
            const parent = activeScreen.value.widgets.find(w => w.id === selectedWidgetId.value);
            if (parent) {
                if (parent.type === WIDGET_TYPES.BUTTON || parent.type === WIDGET_TYPES.TABPAGE) {
                    parentId = parent.id;
                    startX = 10;
                    startY = 10;
                } else if (parent.type === WIDGET_TYPES.TABVIEW && typeStr === 'tabpage') {
                    parentId = parent.id;
                    startX = 0;
                    startY = 0;
                } else if (parent.type === WIDGET_TYPES.POWERFLOW && typeStr === 'powernode') {
                    parentId = parent.id;
                    startX = 40;
                    startY = 40;
                } else if (parent.type === WIDGET_TYPES.POWERNODE && typeStr === 'powernode') {
                    const grandParent = activeScreen.value.widgets.find(w => w.id === parent.parentId);
                    if (grandParent && grandParent.type === WIDGET_TYPES.POWERFLOW) {
                        parentId = grandParent.id;
                        startX = 40;
                        startY = 40;
                    }
                }
            }
        }
        
        const w = {
            id: nextWidgetId.value++,
            parentId: parentId,
            type: typeValue,
            x: startX,
            y: startY,
            w: defaults.w,
            h: defaults.h,
            visible: true,
            textSrc: defaults.textSrc,
            text: defaults.text,
            knxAddr: defaults.knxAddr,
            fontSize: defaults.fontSize,
            textAlign: defaults.textAlign,
            isContainer: defaults.isContainer,
            textColor: defaults.textColor,
            bgColor: defaults.bgColor,
            bgOpacity: defaults.bgOpacity,
            radius: defaults.radius,
            shadow: { ...defaults.shadow },
            isToggle: defaults.isToggle,
            knxAddrWrite: defaults.knxAddrWrite,
            action: defaults.action,
            targetScreen: defaults.targetScreen,
            iconCodepoint: defaults.iconCodepoint || 0,
            iconPosition: defaults.iconPosition || 0,
            iconSize: defaults.iconSize || 1,
            iconGap: defaults.iconGap || 8
        };
        
        activeScreen.value.widgets.push(w);
        selectedWidgetId.value = w.id;

        if (typeStr === 'button') {
            const labelDefaults = WIDGET_DEFAULTS.label;
            const label = {
                id: nextWidgetId.value++,
                parentId: w.id,
                type: WIDGET_TYPES.LABEL,
                x: 0,
                y: 0,
                w: w.w,
                h: w.h,
                visible: true,
                textSrc: labelDefaults.textSrc,
                text: w.text,
                knxAddr: labelDefaults.knxAddr,
                fontSize: w.fontSize,
                textAlign: TEXT_ALIGNS.CENTER,
                textColor: w.textColor,
                bgColor: labelDefaults.bgColor,
                bgOpacity: 0,
                radius: 0,
                shadow: { ...labelDefaults.shadow, enabled: false },
                isToggle: false,
                knxAddrWrite: 0,
                action: 0,
                targetScreen: 0,
                iconCodepoint: w.iconCodepoint || 0,
                iconPosition: w.iconPosition || 0,
                iconSize: w.iconSize || 1,
                iconGap: w.iconGap || 8
            };
            activeScreen.value.widgets.push(label);
        }

        // Auto-create pages for new TabView
        if (typeStr === 'tabview') {
            // Deselect to reset parent logic for recursive calls, or explicitly pass parent
            // Easier: just manually push 2 pages
            const p1 = { ...WIDGET_DEFAULTS.tabpage, id: nextWidgetId.value++, parentId: w.id, text: 'Tab 1', type: WIDGET_TYPES.TABPAGE };
            const p2 = { ...WIDGET_DEFAULTS.tabpage, id: nextWidgetId.value++, parentId: w.id, text: 'Tab 2', type: WIDGET_TYPES.TABPAGE };
            activeScreen.value.widgets.push(p1);
            activeScreen.value.widgets.push(p2);
        }
    }

    function setPowerLinkMode(active, powerflowId = null) {
        powerLinkMode.active = active;
        powerLinkMode.powerflowId = active ? powerflowId : null;
        powerLinkMode.fromNodeId = null;
    }

    function addPowerLink(powerflowId, fromNodeId, toNodeId) {
        if (!activeScreen.value) return;
        if (fromNodeId === toNodeId) return;

        const existing = activeScreen.value.widgets.find((w) => {
            if (w.parentId !== powerflowId || w.type !== WIDGET_TYPES.POWERLINK) return false;
            return (w.x === fromNodeId && w.y === toNodeId) || (w.x === toNodeId && w.y === fromNodeId);
        });

        if (existing) return;

        const defaults = WIDGET_DEFAULTS.powerlink;
        const link = {
            id: nextWidgetId.value++,
            parentId: powerflowId,
            type: WIDGET_TYPES.POWERLINK,
            x: fromNodeId,
            y: toNodeId,
            w: defaults.w,
            h: defaults.h,
            visible: true,
            textSrc: defaults.textSrc,
            text: defaults.text,
            knxAddr: defaults.knxAddr,
            fontSize: defaults.fontSize,
            textAlign: defaults.textAlign,
            isContainer: false,
            textColor: defaults.textColor,
            bgColor: defaults.bgColor,
            bgOpacity: defaults.bgOpacity,
            radius: defaults.radius,
            shadow: { ...defaults.shadow },
            isToggle: defaults.isToggle,
            knxAddrWrite: defaults.knxAddrWrite,
            action: defaults.action,
            targetScreen: defaults.targetScreen,
            iconCodepoint: defaults.iconCodepoint || 0,
            iconPosition: defaults.iconPosition || 0,
            iconSize: defaults.iconSize || 0,
            iconGap: defaults.iconGap || 0
        };

        activeScreen.value.widgets.push(link);
    }

    function removePowerLink(linkId) {
        if (!activeScreen.value) return;
        activeScreen.value.widgets = activeScreen.value.widgets.filter(w => w.id !== linkId);
    }

    function handlePowerNodeLink(nodeId, powerflowId) {
        if (!powerLinkMode.active || powerLinkMode.powerflowId !== powerflowId) {
            selectedWidgetId.value = nodeId;
            return;
        }

        if (!powerLinkMode.fromNodeId || powerLinkMode.fromNodeId === nodeId) {
            powerLinkMode.fromNodeId = nodeId;
            return;
        }

        addPowerLink(powerflowId, powerLinkMode.fromNodeId, nodeId);
        powerLinkMode.fromNodeId = nodeId;
    }

    function deleteWidget() {
        if (!activeScreen.value || selectedWidgetId.value === null) return;
        
        // Also delete children recursively? 
        // For now, simpler: reparent children to root or delete them.
        // Let's delete them to avoid orphans.
        const idToDelete = selectedWidgetId.value;
        const deleteIds = [idToDelete];
        
        // Find all descendants
        let found = true;
        while (found) {
            found = false;
            activeScreen.value.widgets.forEach(w => {
                if (deleteIds.includes(w.parentId) && !deleteIds.includes(w.id)) {
                    deleteIds.push(w.id);
                    found = true;
                }
            });
        }

        // Remove power links connected to deleted nodes
        activeScreen.value.widgets.forEach((w) => {
            if (w.type === WIDGET_TYPES.POWERLINK) {
                if (deleteIds.includes(w.x) || deleteIds.includes(w.y)) {
                    deleteIds.push(w.id);
                }
            }
        });
        
        activeScreen.value.widgets = activeScreen.value.widgets.filter(w => !deleteIds.includes(w.id));
        selectedWidgetId.value = null;
    }

    function reparentWidget(widgetId, newParentId) {
        if (!activeScreen.value) return;
        
        // Prevent cycles: Check if newParentId is a descendant of widgetId
        let curr = newParentId;
        while (curr !== -1) {
            if (curr === widgetId) return; // Cycle detected
            const p = activeScreen.value.widgets.find(w => w.id === curr);
            if (!p) break;
            curr = p.parentId;
        }

        const widget = activeScreen.value.widgets.find(w => w.id === widgetId);
        if (widget) {
            // Adjust position to be relative to new parent (simplified: reset to 0,0 or keep absolute?)
            // Keeping absolute is hard because we don't know absolute pos easily here.
            // Resetting to 10,10 is safer.
            widget.x = 10;
            widget.y = 10;
            widget.parentId = newParentId;
        }
    }

    return {
        config,
        knxAddresses,
        selectedWidgetId,
        activeScreenId,
        canvasScale,
        showGrid,
        snapToGrid,
        gridSize,
        powerLinkMode,
        activeScreen,
        widgetTree,
        selectedWidget,
        loadKnxAddresses,
        loadConfig,
        saveConfig,
        resetConfig,
        addScreen,
        deleteScreen,
        addWidget,
        setPowerLinkMode,
        addPowerLink,
        removePowerLink,
        handlePowerNodeLink,
        deleteWidget,
        reparentWidget
    };
});
