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 },
        knx: { time: 0, date: 0, dateTime: 0, night: 0 },
        screenAnim: { type: 1, duration: 300 },  // 1 = Fade, 300ms
        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 nightPreview = ref(false);
    const powerLinkMode = reactive({ active: false, powerflowId: null, fromNodeId: null });

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

    function mapLegacyKnxAddresses() {
        if (!knxAddresses.value.length || !Array.isArray(config.screens)) return;
        const addrByIndex = new Map();
        const gaSet = new Set();
        knxAddresses.value.forEach((addr) => {
            if (typeof addr.index === 'number' && typeof addr.addr === 'number') {
                addrByIndex.set(addr.index, addr.addr);
                gaSet.add(addr.addr);
            }
        });

        config.screens.forEach((screen) => {
            if (!Array.isArray(screen.widgets)) return;
            screen.widgets.forEach((w) => {
                if (typeof w.knxAddr === 'number' && w.knxAddr > 0) {
                    if (!gaSet.has(w.knxAddr) && addrByIndex.has(w.knxAddr)) {
                        w.knxAddr = addrByIndex.get(w.knxAddr);
                    }
                }
                if (typeof w.knxAddrWrite === 'number' && w.knxAddrWrite > 0) {
                    if (!gaSet.has(w.knxAddrWrite) && addrByIndex.has(w.knxAddrWrite)) {
                        w.knxAddrWrite = addrByIndex.get(w.knxAddrWrite);
                    }
                }
                // PowerNode secondary/tertiary addresses
                if (typeof w.knxAddr2 === 'number' && w.knxAddr2 > 0) {
                    if (!gaSet.has(w.knxAddr2) && addrByIndex.has(w.knxAddr2)) {
                        w.knxAddr2 = addrByIndex.get(w.knxAddr2);
                    }
                }
                if (typeof w.knxAddr3 === 'number' && w.knxAddr3 > 0) {
                    if (!gaSet.has(w.knxAddr3) && addrByIndex.has(w.knxAddr3)) {
                        w.knxAddr3 = addrByIndex.get(w.knxAddr3);
                    }
                }
                if (w.chart && Array.isArray(w.chart.series)) {
                    w.chart.series.forEach((series) => {
                        if (typeof series.knxAddr === 'number' && series.knxAddr > 0) {
                            if (!gaSet.has(series.knxAddr) && addrByIndex.has(series.knxAddr)) {
                                series.knxAddr = addrByIndex.get(series.knxAddr);
                            }
                        }
                    });
                }
            });
        });

        if (config.knx) {
            if (typeof config.knx.time === 'number' && config.knx.time > 0) {
                if (!gaSet.has(config.knx.time) && addrByIndex.has(config.knx.time)) {
                    config.knx.time = addrByIndex.get(config.knx.time);
                }
            }
            if (typeof config.knx.date === 'number' && config.knx.date > 0) {
                if (!gaSet.has(config.knx.date) && addrByIndex.has(config.knx.date)) {
                    config.knx.date = addrByIndex.get(config.knx.date);
                }
            }
            if (typeof config.knx.dateTime === 'number' && config.knx.dateTime > 0) {
                if (!gaSet.has(config.knx.dateTime) && addrByIndex.has(config.knx.dateTime)) {
                    config.knx.dateTime = addrByIndex.get(config.knx.dateTime);
                }
            }
            if (typeof config.knx.night === 'number' && config.knx.night > 0) {
                if (!gaSet.has(config.knx.night) && addrByIndex.has(config.knx.night)) {
                    config.knx.night = addrByIndex.get(config.knx.night);
                }
            }
        }
    }

    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 cleanupButtonLabels(screen) {
        if (!screen || !Array.isArray(screen.widgets)) return;

        const buttonIds = new Set(
            screen.widgets.filter(w => w.type === WIDGET_TYPES.BUTTON).map(w => w.id)
        );
        if (!buttonIds.size) return;

        const removeIds = new Set();
        screen.widgets.forEach((w) => {
            if (w.type === WIDGET_TYPES.LABEL && buttonIds.has(w.parentId)) {
                removeIds.add(w.id);
            }
        });

        if (removeIds.size) {
            screen.widgets = screen.widgets.filter(w => !removeIds.has(w.id));
        }

        // Update container flag for buttons based on remaining children
        screen.widgets.forEach((w) => {
            if (w.type !== WIDGET_TYPES.BUTTON) return;
            const hasChild = screen.widgets.some(child => child.parentId === w.id);
            w.isContainer = hasChild;
        });
    }

    async function loadKnxAddresses() {
        try {
            // Mock or Real API
            const resp = await fetch('/api/knx/addresses');
            if (resp.ok) {
                knxAddresses.value = await resp.json();
                mapLegacyKnxAddresses();
            } 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 };
                 config.knx = { time: 0, date: 0, dateTime: 0, night: 0 };
            }

            if (!config.standby) {
                config.standby = { enabled: false, screen: -1, minutes: 5 };
            }
            if (!config.knx) {
                config.knx = { time: 0, date: 0, dateTime: 0, night: 0 };
            } else {
                if (config.knx.time === undefined) config.knx.time = 0;
                if (config.knx.date === undefined) config.knx.date = 0;
                if (config.knx.dateTime === undefined) config.knx.dateTime = 0;
                if (config.knx.night === undefined) config.knx.night = 0;
            }
            if (!config.screenAnim) {
                config.screenAnim = { type: 1, duration: 300 };
            } else {
                if (config.screenAnim.type === undefined) config.screenAnim.type = 1;
                if (config.screenAnim.duration === undefined) config.screenAnim.duration = 300;
            }
            mapLegacyKnxAddresses();

            // 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);
                cleanupButtonLabels(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',
            nightBgColor: '#0E1217',
            bgImage: '',
            bgImageMode: 1,
            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;
            case 'chart': typeValue = WIDGET_TYPES.CHART; break;
            case 'clock': typeValue = WIDGET_TYPES.CLOCK; break;
            case 'roomcard': typeValue = WIDGET_TYPES.ROOMCARD; break;
            case 'rectangle': typeValue = WIDGET_TYPES.RECTANGLE; break;
            case 'arc': typeValue = WIDGET_TYPES.ARC; break;
            case 'buttonmatrix': typeValue = WIDGET_TYPES.BUTTONMATRIX; 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,
            borderWidth: defaults.borderWidth ?? 0,
            borderColor: defaults.borderColor || '#ffffff',
            borderOpacity: defaults.borderOpacity ?? 0,
            arcMin: defaults.arcMin ?? 0,
            arcMax: defaults.arcMax ?? 100,
            arcUnit: defaults.arcUnit ?? 0,
            arcShowValue: defaults.arcShowValue ?? true,
            arcScaleOffset: defaults.arcScaleOffset ?? 0,
            arcScaleColor: defaults.arcScaleColor ?? defaults.textColor,
            arcValueColor: defaults.arcValueColor ?? defaults.textColor,
            arcValueFontSize: defaults.arcValueFontSize ?? defaults.fontSize,
            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,
            iconPositionX: defaults.iconPositionX || 8,
            iconPositionY: defaults.iconPositionY || 8,
            themeFixed: defaults.themeFixed ?? false
        };

        if (defaults.conditions !== undefined) {
            w.conditions = [];
        }

        if (defaults.chart) {
            w.chart = {
                period: defaults.chart.period ?? 0,
                series: (defaults.chart.series || []).map(s => ({ ...s }))
            };
        }

        // PowerNode: secondary/tertiary values and conditions
        if (typeStr === 'powernode') {
            w.textSrc2 = defaults.textSrc2 ?? 0;
            w.text2 = defaults.text2 ?? '';
            w.knxAddr2 = defaults.knxAddr2 ?? 0;
            w.textSrc3 = defaults.textSrc3 ?? 0;
            w.text3 = defaults.text3 ?? '';
            w.knxAddr3 = defaults.knxAddr3 ?? 0;
            w.conditions = [];
        }

        // RoomCard: initialize sub-buttons and text lines arrays
        if (typeStr === 'roomcard') {
            w.subButtons = [];
            w.textLines = [];
        }

        activeScreen.value.widgets.push(w);
        selectedWidgetId.value = w.id;

        // 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,
            iconPositionX: defaults.iconPositionX || 0,
            iconPositionY: defaults.iconPositionY || 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);
                }
            }
        });
        
        const parentIds = new Set();
        activeScreen.value.widgets.forEach((w) => {
            if (deleteIds.includes(w.id) && w.parentId !== -1) {
                parentIds.add(w.parentId);
            }
        });

        activeScreen.value.widgets = activeScreen.value.widgets.filter(w => !deleteIds.includes(w.id));

        parentIds.forEach((pid) => {
            const parent = activeScreen.value.widgets.find(w => w.id === pid);
            if (parent && parent.type === WIDGET_TYPES.BUTTON) {
                const hasChild = activeScreen.value.widgets.some(w => w.parentId === pid);
                parent.isContainer = hasChild;
            }
        });
        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) {
            const oldParentId = widget.parentId;
            // 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;

            if (oldParentId !== -1) {
                const oldParent = activeScreen.value.widgets.find(w => w.id === oldParentId);
                if (oldParent && oldParent.type === WIDGET_TYPES.BUTTON) {
                    const hasChild = activeScreen.value.widgets.some(w => w.parentId === oldParentId);
                    oldParent.isContainer = hasChild;
                }
            }

            const newParent = activeScreen.value.widgets.find(w => w.id === newParentId);
            if (newParent && newParent.type === WIDGET_TYPES.BUTTON) {
                newParent.isContainer = true;
            }
        }
    }

    function findSiblingIndex(widgetId, direction) {
        if (!activeScreen.value) return -1;
        const widgets = activeScreen.value.widgets;
        const idx = widgets.findIndex(w => w.id === widgetId);
        if (idx < 0) return -1;

        const parentId = widgets[idx].parentId;
        if (direction === 'up') {
            for (let i = idx - 1; i >= 0; i--) {
                if (widgets[i].parentId === parentId && widgets[i].type !== WIDGET_TYPES.POWERLINK) {
                    return i;
                }
            }
        } else {
            for (let i = idx + 1; i < widgets.length; i++) {
                if (widgets[i].parentId === parentId && widgets[i].type !== WIDGET_TYPES.POWERLINK) {
                    return i;
                }
            }
        }
        return -1;
    }

    function canMoveWidget(widgetId, direction) {
        return findSiblingIndex(widgetId, direction) !== -1;
    }

    function moveWidget(widgetId, direction) {
        if (!activeScreen.value) return;
        const widgets = activeScreen.value.widgets;
        const idx = widgets.findIndex(w => w.id === widgetId);
        if (idx < 0) return;

        const targetIdx = findSiblingIndex(widgetId, direction);
        if (targetIdx < 0) return;

        const tmp = widgets[idx];
        widgets[idx] = widgets[targetIdx];
        widgets[targetIdx] = tmp;
    }

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