import { ref } from 'vue'
import { defWindows } from './WindowDefinitions';
import { defineAsyncComponent } from 'vue'

const componentCache = {}

const getComponent = (type) => {
  if (!componentCache[type]) {
    componentCache[type] = defineAsyncComponent(
      defWindows[type].component
    )
  }

  return componentCache[type]
}

const windows = ref([]);
let WindowMap = () => { return windowMap };

let currentIndex = 10;
let currentId = 0;

function SetupHandle(id, handle) {

    // Update window info with handle info
    let win = GetWindowWithId(id);

    let currentWindowId = "window-wrapper-" + id;
    let currentWindowHandleId = "window-handle-" + id;
    let currentWindowResizerId = "window-resize-handle-" + id;

    let draggingWindow = false;
    let resizingWindow = false;

    let currentWindow = document.getElementById(currentWindowId);
    let handler = document.getElementById(currentWindowHandleId);
    let resizer = document.getElementById(currentWindowResizerId);

    let offsetX = 0;
    let offsetY = 0;

    let resizeOffsetX = 0;
    let resizeOffsetY = 0;

    // Programar un resizer mitjanament competent

    currentWindow.addEventListener("mousedown", (event) => {
        SetOnTop(id);
    });

    // Move window listeners
    handler.addEventListener("mousedown", (event) => {
        if(!win.movable) return;
        draggingWindow = true;

        let windowRect = currentWindow.getBoundingClientRect();
        offsetX = windowRect.left - event.clientX;
        offsetY = windowRect.top - event.clientY;
    })

    document.addEventListener("mousemove", (event) => {
        if(!win.movable) return;
        if (!draggingWindow) return;

        if (event.clientX + offsetX < -currentWindow.getBoundingClientRect().width + 20) currentWindow.style.left = (-currentWindow.getBoundingClientRect().width + 20) + "px";
        else if (event.clientX + offsetX > window.innerWidth - 20) currentWindow.style.left = (window.innerWidth - 20) + "px";
        else currentWindow.style.left = (event.clientX + offsetX) + "px";

        if (event.clientY + offsetY < 0) currentWindow.style.top = (0) + "px";
        else if (event.clientY + offsetY > window.innerHeight - 20) currentWindow.style.top = (window.innerHeight - 20) + "px";
        else currentWindow.style.top = (event.clientY + offsetY) + "px";
    })

    document.addEventListener("mouseup", (event) => {
        if(!win.movable) return;
        draggingWindow = false;
        // ummm suposo que no pots tancar mentres mous?
        SaveWindowPos({ id, x: parseInt(currentWindow.style.left, 10), y: parseInt(currentWindow.style.top, 10) });
    });

    // Resize window listeners
    resizer.addEventListener("mousedown", (event) => {
        resizingWindow = true;

        let windowRect = currentWindow.getBoundingClientRect();
        resizeOffsetX = parseInt(currentWindow.style.width) - event.clientX;
        resizeOffsetY = parseInt(currentWindow.style.height) - event.clientY;
    });

    document.addEventListener("mousemove", (event) => {
        if (!resizingWindow) return;

        let newWidth = event.clientX + resizeOffsetX;
        let newHeight = event.clientY + resizeOffsetY;

        if (win.minHeight) if (win.minHeight > newHeight) newHeight = win.minHeight;
        if (win.maxHeight) if (win.maxHeight < newHeight) newHeight = win.maxHeight;

        if (win.minWidth) if (win.minWidth > newWidth) newWidth = win.minWidth;
        if (win.maxWidth) if (win.maxWidth < newWidth) newWidth = win.maxWidth;

        currentWindow.style.width = newWidth + "px";
        currentWindow.style.height = newHeight + "px";
    });

    document.addEventListener("mouseup", (event) => {
        resizingWindow = false;

        win.width = parseInt(currentWindow.style.width, 10);
        win.height = parseInt(currentWindow.style.height, 10);
    });

    // Should move eventually?
    window.addEventListener('resize', (event) => {
        for(const w of windows.value){
            if(w.movable) continue;
            ResetPosition(w.id, "center");
        }
    })

    handle.value.setupHandle();
}

function SetResizable(id, resizable) {
    let win = GetWindowWithId(id);
    win.resizable = resizable;
}

function SetMovable(id, movable) {
    let win = GetWindowWithId(id);
    win.movable = movable;
}

function SetSize(id, size) {
    let currentWindowId = "window-wrapper-" + id;
    let currentWindow = document.getElementById(currentWindowId);
    let win = GetWindowWithId(id);

    currentWindow.style.width = size.width + "px";
    currentWindow.style.height = size.height + "px";

    win.width = size.width;
}

function SetMaxSize(id, maxSize) {
    let win = GetWindowWithId(id);

    if (maxSize.width) win.maxWidth = maxSize.width;
    else win.maxWidth = win.width;

    if (maxSize.height) win.maxHeight = maxSize.height;
    else win.maxHeight = win.height;
}

function SetMinSize(id, minSize) {
    let win = GetWindowWithId(id);

    if (minSize.width) win.minWidth = minSize.width;
    else win.minWidth = win.width;

    if (minSize.height) win.minHeight = minSize.height;
    else win.minHeight = win.height;
}

function SetPosition(id, pos) {
    let currentWindowId = "window-wrapper-" + id;
    let currentWindow = document.getElementById(currentWindowId);

    if (pos == "center") {
        let x = window.innerWidth / 2;
        let y = window.innerHeight / 2;

        currentWindow.style.left = (x - currentWindow.getBoundingClientRect().width / 2) + "px";
        currentWindow.style.top = (y - currentWindow.getBoundingClientRect().height / 2) + "px";

        return;
    }

    currentWindow.style.top = pos.y + "px";
    currentWindow.style.left = pos.x + "px";

    SaveWindowPos({ id, x: pos.x, y: pos.y })
}

function GetPosition(id) {
    let win = GetWindowWithId(id);
    return { x: win.x, y: win.y };
}

function ResetPosition(id, pos) {
    let win = GetWindowWithId(id);
    if (!win) return;
    let data = { x: win.x, y: win.y };

    if (data.x && data.y) {
        SetPosition(id, data);
        return;
    }
    SetPosition(id, pos);
}


function CreateWindow(type, data = {}) {
    let finalData = { ...{ type, id: currentId }, ...defWindows[type], ...data }
    currentId++;
    
    let contains = false;
    for (let i = 0; i < windows.value.length; i++) {
        if (windows.value[i].type == finalData.type) {
            contains = true;
            break;
        }
    }
    if (!contains) {
        windows.value.push(finalData);
        setTimeout(() => {
            if (finalData.create) finalData.create();
        }, 0);
    }
}

function CreateChildWindow(parentId, type, data = {}) {
    const newId = currentId;
    let parent = GetWindowWithId(parentId);
    if (parent.children) parent.children.push(newId); // We will create the child window right now
    else parent.children = [newId];
    CreateWindow(type, data);
}

function GetFirstWindowId(type) {
    for (let i = 0; i < windows.value.length; i++) {
        if (windows.value[i].type == type) return windows.value[i].id;
    }
}

function ClearAll() {
    Object.keys(windows).forEach((key) => {
        windows.value = [];
    });
}

function clearWindowById(id){
    let win = GetWindowWithId(id);
    if (!win) return;
    if (win.children) for (let i = 0; i < win.children.length; i++) clearWindowById(win.children[i]);
    const index = windows.value.findIndex(w => w.id === id)
    if (index !== -1) windows.value.splice(index, 1)
}

function ClearWindow(selector) {
    if(selector.type !== undefined) {
        const type = selector.type;
        for(let i = 0; i < windows.value.length; i++) {
            if(windows.value[i].type == type) {
                clearWindowById(windows.value[i].id);
                break;
            }
        }
    }
    if(selector.id !== undefined) {
        const id = selector.id;
        clearWindowById(id);
    }
    
    // reload.value += 1;
}

function GetWindowWithId(id) {
    const index = windows.value.findIndex(w => w.id === id);
    if (index !== -1) return windows.value[index];
}

function CallWindow(id, callableName, arg) {
    let win = GetWindowWithId(id);
    win[callableName](arg);
}

function SaveWindowPos(data) {
    let win = GetWindowWithId(data.id);
    if (win === undefined) return;
    win.x = data.x;
    win.y = data.y;
}

function SetOnTop(id) {
    let currentWindowId = "window-wrapper-" + id;
    let currentWindow = document.getElementById(currentWindowId);

    try {
        currentIndex += 1;
        currentWindow.style.zIndex = currentIndex;
    } catch(e) {}
}

function Top(element) {
    try {
        currentIndex += 1;
        element.value.style.zIndex = currentIndex;
    } catch(e) {}
}

export {
    windows,
    SetupHandle,
    SetSize,
    SetResizable,
    SetMaxSize,
    SetMinSize,
    SetPosition,
    SetMovable,
    ResetPosition,
    WindowMap,
    CreateWindow,
    CreateChildWindow,
    GetFirstWindowId,
    CallWindow,
    GetWindowWithId,
    SaveWindowPos,
    GetPosition,
    ClearWindow,
    ClearAll,
    Top,
    getComponent
}