// app/Taskbar.tsx

'use client';

import React from 'react';
import { useWindowManager } from '../contexts/WindowManagerContext';

const Taskbar: React.FC = () => {
  const { windows, windowStates, openWindow, restoreWindow, minimizeWindow } = useWindowManager();

  return (
    <div className="fixed bottom-0 left-0 right-0 bg-gray-800 h-10 flex items-center px-2">
      {Object.keys(windows).map((name) => {
        const state = windowStates[name];
        if (!state) return null;

        let buttonStyle = 'bg-gray-600 text-white px-4 py-1 mx-1 rounded hover:bg-gray-500';

        if (state.visible && !state.minimized) {
          // Window is open
          buttonStyle = 'bg-blue-600 text-white px-4 py-1 mx-1 rounded hover:bg-blue-500';
        } else if (state.minimized) {
          // Window is minimized
          buttonStyle = 'bg-yellow-500 text-white px-4 py-1 mx-1 rounded hover:bg-yellow-400';
        } else {
          // Window is closed
          buttonStyle = 'bg-gray-600 text-white px-4 py-1 mx-1 rounded hover:bg-gray-500';
        }

        const handleClick = () => {
          if (state.visible && !state.minimized) {
            // Window is open and not minimized, minimize it
            minimizeWindow(name);
          } else if (state.minimized) {
            // Restore minimized window
            restoreWindow(name);
          } else {
            // Open window
            openWindow(name);
          }
        };

        return (
          <button key={name} onClick={handleClick} className={buttonStyle}>
            {name}
          </button>
        );
      })}
    </div>
  );
};

export default Taskbar;

AND:

// contexts/WindowManagerContext.tsx

'use client';

import React, { createContext, useContext, useState, useEffect } from 'react';

type WindowProps = {
  width?: string;
  height?: string;
  initialState?: 'open' | 'closed' | 'minimized';
  gravity?: number; // Existing gravity property
  initialX?: string; // New initialX property
  initialY?: string; // New initialY property
  windowTitle?: string; // New windowTitle property
};

type WindowData = {
  name: string;
  Component: React.ComponentType;
  windowProps: WindowProps;
};

type WindowState = {
  visible: boolean;
  minimized: boolean;
  maximized: boolean;
  width: number;
  height: number;
  x: number;
  y: number;
  zIndex: number;
  windowTitle: string; // Added windowTitle to WindowState for easy access
  prevWidth?: number;
  prevHeight?: number;
  prevX?: number;
  prevY?: number;
};

type WindowManagerContextType = {
  windows: { [key: string]: WindowData };
  windowStates: { [key: string]: WindowState };
  openWindow: (name: string) => void;
  closeWindow: (name: string) => void;
  minimizeWindow: (name: string) => void;
  restoreWindow: (name: string) => void;
  maximizeWindow: (name: string) => void;
  updateWindowState: (name: string, newState: Partial<WindowState>, skipGrid?: boolean) => void;
  bringToFront: (name: string) => void;
};

const WindowManagerContext = createContext<WindowManagerContextType | undefined>(undefined);

export const useWindowManager = () => {
  const context = useContext(WindowManagerContext);
  if (!context) {
    throw new Error('useWindowManager must be used within a WindowManagerProvider');
  }
  return context;
};

export const WindowManagerProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [windows, setWindows] = useState<{ [key: string]: WindowData }>({});
  const [windowStates, setWindowStates] = useState<{ [key: string]: WindowState }>({});
  const [nextZIndex, setNextZIndex] = useState(1);

  // Define grid size constant
  const GRID_SIZE = 25;

  type WindowDataAndState = {
    windowData: WindowData;
    windowState: WindowState;
  };

  useEffect(() => {
    // Dynamically import window components
    const importWindows = async () => {
      // Replace with your actual dynamic import logic if needed
      const windowsContext = require.context('../windows', false, /\.tsx$/);
      const windowFiles = windowsContext.keys();

      let zIndexCounter = 1;

      const windowsDataPromises: Promise<WindowDataAndState>[] = windowFiles.map(
        async (file: string, index: number): Promise<WindowDataAndState> => {
          const mod = await windowsContext(file);
          const name = file.replace('./', '').replace('.tsx', '');
          const Component = mod.default;
          const windowProps: WindowProps = mod.windowProps || {};

          // Parse initial size
          let width = windowProps.width
            ? parseSize(windowProps.width, 'width')
            : 0.35 * window.innerWidth;
          let height = windowProps.height
            ? parseSize(windowProps.height, 'height')
            : 0.2 * window.innerHeight;

          // Adjust width and height to align with grid
          width = Math.round(width / GRID_SIZE) * GRID_SIZE;
          height = Math.round(height / GRID_SIZE) * GRID_SIZE;

          // Parse initial position
          let x = windowProps.initialX
            ? parseSize(windowProps.initialX, 'width') // Use 'width' for initialX
            : 100 + index * 50; // Default value if initialX not provided
          let y = windowProps.initialY
            ? parseSize(windowProps.initialY, 'height') // Use 'height' for initialY
            : 100 + index * 50; // Default value if initialY not provided

          // Adjust x and y to align with grid
          x = Math.round(x / GRID_SIZE) * GRID_SIZE;
          y = Math.round(y / GRID_SIZE) * GRID_SIZE;

          // Determine initial state
          const initialState = windowProps.initialState || 'open';
          let visible = true;
          let minimized = false;

          switch (initialState) {
            case 'open':
              visible = true;
              minimized = false;
              break;
            case 'closed':
              visible = false;
              minimized = false;
              break;
            case 'minimized':
              visible = false;
              minimized = true;
              break;
            default:
              visible = true;
              minimized = false;
              break;
          }

          const windowData: WindowData = { name, Component, windowProps };
          const windowTitle = windowProps.windowTitle || name; // Use windowTitle prop or default to name
          const windowState: WindowState = {
            visible,
            minimized,
            maximized: false,
            width,
            height,
            x,
            y,
            zIndex: zIndexCounter++,
            windowTitle, // Store windowTitle in state
          };

          return { windowData, windowState };
        }
      );

      const windowsDataArray: WindowDataAndState[] = await Promise.all(windowsDataPromises);

      const newWindows: { [key: string]: WindowData } = {};
      const newWindowStates: { [key: string]: WindowState } = {};

      windowsDataArray.forEach(({ windowData, windowState }) => {
        newWindows[windowData.name] = windowData;
        newWindowStates[windowData.name] = windowState;
      });

      setWindows(newWindows);
      setWindowStates(newWindowStates);
      setNextZIndex(zIndexCounter);
    };

    importWindows();
  }, []);

  const bringToFront = (name: string) => {
    setWindowStates((prev) => {
      const maxZ = nextZIndex;
      setNextZIndex(maxZ + 1);
      return {
        ...prev,
        [name]: {
          ...prev[name],
          zIndex: maxZ,
        },
      };
    });
  };

  const openWindow = (name: string) => {
    setWindowStates((prev) => ({
      ...prev,
      [name]: {
        ...prev[name],
        visible: true,
        minimized: false,
      },
    }));
    bringToFront(name);
  };

  const closeWindow = (name: string) => {
    setWindowStates((prev) => ({
      ...prev,
      [name]: {
        ...prev[name],
        visible: false,
        minimized: false,
      },
    }));
  };

  const minimizeWindow = (name: string) => {
    setWindowStates((prev) => ({
      ...prev,
      [name]: {
        ...prev[name],
        minimized: true,
        visible: false,
      },
    }));
  };

  const restoreWindow = (name: string) => {
    setWindowStates((prev) => ({
      ...prev,
      [name]: {
        ...prev[name],
        minimized: false,
        visible: true,
      },
    }));
    bringToFront(name);
  };

  const maximizeWindow = (name: string) => {
    setWindowStates((prev) => {
      const state = prev[name];
      const isMaximized = !state.maximized;

      if (isMaximized) {
        // Store previous size and position
        const prevSizePosition = {
          prevWidth: state.width,
          prevHeight: state.height,
          prevX: state.x,
          prevY: state.y,
        };

        const maxWidth = window.innerWidth - 20; // Adjusted width for spacing
        const maxHeight = window.innerHeight - 20; // Adjusted height for spacing

        // Adjust to align with grid
        const adjustedWidth = Math.floor(maxWidth / GRID_SIZE) * GRID_SIZE;
        const adjustedHeight = Math.floor(maxHeight / GRID_SIZE) * GRID_SIZE;

        return {
          ...prev,
          [name]: {
            ...state,
            maximized: true,
            ...prevSizePosition,
            x: 10, // Adjusted for spacing when maximized
            y: 10, // Adjusted for spacing when maximized
            width: adjustedWidth,
            height: adjustedHeight,
          },
        };
      } else {
        // Restore previous size and position
        return {
          ...prev,
          [name]: {
            ...state,
            maximized: false,
            width: state.prevWidth || state.width,
            height: state.prevHeight || state.height,
            x: state.prevX || state.x,
            y: state.prevY || state.y,
          },
        };
      }
    });
    bringToFront(name);
  };

  const updateWindowState = (
    name: string,
    newState: Partial<WindowState>,
    skipGrid = false
  ) => {
    setWindowStates((prev) => {
      let updatedState = {
        ...prev[name],
        ...newState,
      };

      if (!skipGrid) {
        // Ensure positions and sizes align with the grid
        updatedState.x = Math.round(updatedState.x / GRID_SIZE) * GRID_SIZE;
        updatedState.y = Math.round(updatedState.y / GRID_SIZE) * GRID_SIZE;
        updatedState.width = Math.round(updatedState.width / GRID_SIZE) * GRID_SIZE;
        updatedState.height = Math.round(updatedState.height / GRID_SIZE) * GRID_SIZE;
      }

      return {
        ...prev,
        [name]: updatedState,
      };
    });
  };

  function parseSize(value: string, dimension: 'width' | 'height'): number {
    if (typeof window === 'undefined') return 400;

    value = value.trim();

    if (value.endsWith('%')) {
      const percentage = parseFloat(value) / 100;
      if (dimension === 'width') {
        return percentage * window.innerWidth;
      } else {
        return percentage * window.innerHeight;
      }
    } else if (value.endsWith('px')) {
      return parseFloat(value);
    } else {
      // Assume pixels if unit is missing
      return parseFloat(value);
    }
  }

  return (
    <WindowManagerContext.Provider
      value={{
        windows,
        windowStates,
        openWindow,
        closeWindow,
        minimizeWindow,
        restoreWindow,
        maximizeWindow,
        updateWindowState,
        bringToFront,
      }}
    >
      {children}
    </WindowManagerContext.Provider>
  );
};

AND:

// app/page.tsx

import DraggableWindows from "./DraggableWindows";
import Taskbar from "./Taskbar";

export default function Page() {
  return (
    <>
      <DraggableWindows />
      <Taskbar />
    </>
  );
}

AND:

// app/layout.tsx

export const metadata = {
  title: 'My Next.js App',
  description: 'A Next.js App with draggable windows',
};

import './globals.css';
import { WindowManagerProvider } from '../contexts/WindowManagerContext';
import AnimatedBackground from '../components/AnimatedBackground';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className="bg-dark-pattern min-h-screen relative overflow-hidden">
        <WindowManagerProvider>
          {/* Include the AnimatedBackground as a client component */}
          <AnimatedBackground />
          {children}
        </WindowManagerProvider>
      </body>
    </html>
  );
}

TASK: Currently when windows are maximised they do underneaeth the taskbar. I do not want this to happen. How can I make it so that windows do not go underneath teh taksbar whne maximised?