import { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
import { jsx } from 'react/jsx-runtime';

// lib/logger.ts
var LEVEL_PRIORITY = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
var ENV = typeof process !== "undefined" && process.env ? process.env : {};
function envGet(key) {
  return ENV[key] ?? ENV[`VITE_${key}`];
}
var NODE_ENV = envGet("NODE_ENV") ?? "development";
var CONFIGURED_LEVEL = (envGet("LOG_LEVEL") ?? (NODE_ENV === "production" ? "info" : "debug")).toUpperCase();
var MIN_PRIORITY = LEVEL_PRIORITY[CONFIGURED_LEVEL] ?? 0;
var DEBUG_FILTER = (envGet("ALMADAR_DEBUG") ?? "").split(",").map((s) => s.trim()).filter(Boolean);
function matchesNamespace(namespace) {
  if (DEBUG_FILTER.length === 0) return true;
  return DEBUG_FILTER.some((pattern) => {
    if (pattern === "*" || pattern === "almadar:*") return true;
    if (pattern.endsWith(":*")) return namespace.startsWith(pattern.slice(0, -1));
    return namespace === pattern;
  });
}
function createLogger(namespace) {
  const nsAllowed = matchesNamespace(namespace);
  const log = (level, message, data, correlationId) => {
    if (LEVEL_PRIORITY[level] < MIN_PRIORITY) return;
    if (level === "DEBUG" && !nsAllowed) return;
    const prefix = `[${namespace}]`;
    const logData = correlationId ? { ...data, cid: correlationId } : data;
    switch (level) {
      case "DEBUG":
        console.debug(prefix, message, logData ?? "");
        break;
      case "INFO":
        console.info(prefix, message, logData ?? "");
        break;
      case "WARN":
        console.warn(prefix, message, logData ?? "");
        break;
      case "ERROR":
        console.error(prefix, message, logData ?? "");
        break;
    }
  };
  return {
    debug: (msg, data, cid) => log("DEBUG", msg, data, cid),
    info: (msg, data, cid) => log("INFO", msg, data, cid),
    warn: (msg, data, cid) => log("WARN", msg, data, cid),
    error: (msg, data, cid) => log("ERROR", msg, data, cid)
  };
}

// hooks/useUISlots.ts
var slotLog = createLogger("almadar:ui:useUISlots");
var DEFAULT_SOURCE_KEY = "__default__";
var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
var ALL_SLOTS = [
  "main",
  "sidebar",
  "modal",
  "drawer",
  "overlay",
  "center",
  "toast",
  "hud-top",
  "hud-bottom",
  "hud-left",
  "hud-right",
  "floating"
];
var DEFAULT_SLOTS = ALL_SLOTS.reduce(
  (acc, slot) => {
    acc[slot] = null;
    return acc;
  },
  {}
);
var DEFAULT_SOURCES = ALL_SLOTS.reduce(
  (acc, slot) => {
    acc[slot] = {};
    return acc;
  },
  {}
);
var idCounter = 0;
function generateId() {
  return `slot-content-${++idCounter}-${Date.now()}`;
}
function aggregateSlot(sources) {
  if (!sources) return null;
  const entries = Object.entries(sources);
  if (entries.length === 0) return null;
  if (entries.length === 1) return entries[0][1];
  const children = entries.map(([, entry]) => ({
    type: entry.pattern,
    ...entry.props
  }));
  const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
  return {
    id: stackId,
    pattern: "stack",
    props: {
      direction: "vertical",
      gap: "lg",
      children
    },
    priority: 0,
    animation: "fade",
    sourceTrait: MULTI_SOURCE_STACK_TRAIT
  };
}
function useUISlotManager() {
  const [sources, setSources] = useState(DEFAULT_SOURCES);
  const subscribersRef = useRef(/* @__PURE__ */ new Set());
  const timersRef = useRef(/* @__PURE__ */ new Map());
  const traitIndexRef = useRef(/* @__PURE__ */ new Map());
  const traitSubscribersRef = useRef(/* @__PURE__ */ new Map());
  const slots = useMemo(() => {
    const out = { ...DEFAULT_SLOTS };
    for (const slot of ALL_SLOTS) {
      out[slot] = aggregateSlot(sources[slot]);
    }
    return out;
  }, [sources]);
  useEffect(() => {
    return () => {
      timersRef.current.forEach((timer) => clearTimeout(timer));
      timersRef.current.clear();
    };
  }, []);
  const notifySubscribers = useCallback((slot, content) => {
    subscribersRef.current.forEach((callback) => {
      try {
        callback(slot, content);
      } catch (error) {
        console.error("[UISlots] Subscriber error:", error);
      }
    });
  }, []);
  const notifyTraitSubscribers = useCallback(
    (traitName, content) => {
      const subs = traitSubscribersRef.current.get(traitName);
      if (!subs) return;
      subs.forEach((callback) => {
        try {
          callback(content);
        } catch (error) {
          console.error(`[UISlots] Trait subscriber error (${traitName}):`, error);
        }
      });
    },
    []
  );
  const indexTraitRender = useCallback(
    (traitName, content) => {
      traitIndexRef.current.set(traitName, content);
    },
    []
  );
  const unindexTrait = useCallback((traitName) => {
    traitIndexRef.current.delete(traitName);
  }, []);
  const render = useCallback(
    (config) => {
      const id = generateId();
      const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
      const content = {
        id,
        pattern: config.pattern,
        props: config.props ?? {},
        priority: config.priority ?? 0,
        animation: config.animation ?? "fade",
        onDismiss: config.onDismiss,
        sourceTrait: config.sourceTrait
      };
      if (config.autoDismissMs && config.autoDismissMs > 0) {
        content.autoDismissAt = Date.now() + config.autoDismissMs;
        const timer = setTimeout(() => {
          setSources((prev) => {
            const slotSources = prev[config.target];
            if (slotSources && slotSources[sourceKey]?.id === id) {
              content.onDismiss?.();
              const next = { ...slotSources };
              delete next[sourceKey];
              const updated = { ...prev, [config.target]: next };
              notifySubscribers(config.target, aggregateSlot(next));
              return updated;
            }
            return prev;
          });
          timersRef.current.delete(id);
        }, config.autoDismissMs);
        timersRef.current.set(id, timer);
      }
      setSources((prev) => {
        const slotSources = prev[config.target] ?? {};
        const existing = slotSources[sourceKey];
        if (existing && existing.priority > content.priority) {
          console.warn(
            `[UISlots] Slot "${config.target}" source "${sourceKey}" already has higher priority content (${existing.priority} > ${content.priority})`
          );
          return prev;
        }
        const nextSources = {
          ...slotSources,
          [sourceKey]: content
        };
        const nextAll = { ...prev, [config.target]: nextSources };
        if (content.sourceTrait) {
          indexTraitRender(content.sourceTrait, content);
          notifyTraitSubscribers(content.sourceTrait, content);
        }
        slotLog.info("slot:written", {
          slot: config.target,
          sourceKey,
          sourceTrait: content.sourceTrait,
          patternType: content.pattern,
          priority: content.priority
        });
        notifySubscribers(config.target, aggregateSlot(nextSources));
        return nextAll;
      });
      return id;
    },
    [notifySubscribers, notifyTraitSubscribers, indexTraitRender]
  );
  const clear = useCallback(
    (slot) => {
      setSources((prev) => {
        const slotSources = prev[slot];
        if (!slotSources || Object.keys(slotSources).length === 0) {
          return prev;
        }
        for (const content of Object.values(slotSources)) {
          const timer = timersRef.current.get(content.id);
          if (timer) {
            clearTimeout(timer);
            timersRef.current.delete(content.id);
          }
          content.onDismiss?.();
          if (content.sourceTrait) {
            unindexTrait(content.sourceTrait);
            notifyTraitSubscribers(content.sourceTrait, null);
          }
        }
        notifySubscribers(slot, null);
        return { ...prev, [slot]: {} };
      });
    },
    [notifySubscribers, notifyTraitSubscribers, unindexTrait]
  );
  const clearBySource = useCallback(
    (slot, sourceTrait) => {
      const sourceKey = sourceTrait;
      setSources((prev) => {
        const slotSources = prev[slot];
        if (!slotSources || !(sourceKey in slotSources)) {
          slotLog.debug("slot:clear-noop", { slot, sourceTrait, reason: !slotSources ? "no-slot" : "no-source" });
          return prev;
        }
        const content = slotSources[sourceKey];
        const timer = timersRef.current.get(content.id);
        if (timer) {
          clearTimeout(timer);
          timersRef.current.delete(content.id);
        }
        content.onDismiss?.();
        if (content.sourceTrait) {
          unindexTrait(content.sourceTrait);
          notifyTraitSubscribers(content.sourceTrait, null);
        }
        const nextSources = { ...slotSources };
        delete nextSources[sourceKey];
        slotLog.info("slot:cleared", { slot, sourceTrait, lastPatternType: content.pattern });
        notifySubscribers(slot, aggregateSlot(nextSources));
        return { ...prev, [slot]: nextSources };
      });
    },
    [notifySubscribers, notifyTraitSubscribers, unindexTrait]
  );
  const clearById = useCallback(
    (id) => {
      setSources((prev) => {
        for (const slot of ALL_SLOTS) {
          const slotSources = prev[slot];
          if (!slotSources) continue;
          const matchKey = Object.keys(slotSources).find(
            (k) => slotSources[k].id === id
          );
          if (!matchKey) continue;
          const content = slotSources[matchKey];
          const timer = timersRef.current.get(id);
          if (timer) {
            clearTimeout(timer);
            timersRef.current.delete(id);
          }
          content.onDismiss?.();
          if (content.sourceTrait) {
            unindexTrait(content.sourceTrait);
            notifyTraitSubscribers(content.sourceTrait, null);
          }
          const nextSources = { ...slotSources };
          delete nextSources[matchKey];
          notifySubscribers(slot, aggregateSlot(nextSources));
          return { ...prev, [slot]: nextSources };
        }
        return prev;
      });
    },
    [notifySubscribers, notifyTraitSubscribers, unindexTrait]
  );
  const clearAll = useCallback(() => {
    timersRef.current.forEach((timer) => clearTimeout(timer));
    timersRef.current.clear();
    setSources((prev) => {
      for (const slot of ALL_SLOTS) {
        const slotSources = prev[slot];
        if (!slotSources) continue;
        for (const content of Object.values(slotSources)) {
          content.onDismiss?.();
          if (content.sourceTrait) {
            notifyTraitSubscribers(content.sourceTrait, null);
          }
        }
        notifySubscribers(slot, null);
      }
      return DEFAULT_SOURCES;
    });
    traitIndexRef.current.clear();
  }, [notifySubscribers, notifyTraitSubscribers]);
  const subscribe = useCallback((callback) => {
    subscribersRef.current.add(callback);
    return () => {
      subscribersRef.current.delete(callback);
    };
  }, []);
  const hasContent = useCallback(
    (slot) => slots[slot] !== null,
    [slots]
  );
  const getContent = useCallback(
    (slot) => slots[slot],
    [slots]
  );
  const getTraitContent = useCallback(
    (traitName) => traitIndexRef.current.get(traitName) ?? null,
    []
  );
  const subscribeTrait = useCallback(
    (traitName, callback) => {
      let set = traitSubscribersRef.current.get(traitName);
      if (!set) {
        set = /* @__PURE__ */ new Set();
        traitSubscribersRef.current.set(traitName, set);
      }
      set.add(callback);
      return () => {
        const s = traitSubscribersRef.current.get(traitName);
        if (!s) return;
        s.delete(callback);
        if (s.size === 0) {
          traitSubscribersRef.current.delete(traitName);
        }
      };
    },
    []
  );
  const updateTraitContent = useCallback(
    (traitName, content) => {
      const id = generateId();
      const fullContent = { ...content, id, sourceTrait: traitName };
      indexTraitRender(traitName, fullContent);
      notifyTraitSubscribers(traitName, fullContent);
      return id;
    },
    [indexTraitRender, notifyTraitSubscribers]
  );
  return {
    slots,
    render,
    clear,
    clearBySource,
    clearById,
    clearAll,
    subscribe,
    hasContent,
    getContent,
    getTraitContent,
    subscribeTrait,
    updateTraitContent
  };
}
var UISlotContext = createContext(null);
function UISlotProvider({ children }) {
  const slotManager = useUISlotManager();
  const contextValue = useMemo(() => slotManager, [slotManager]);
  return /* @__PURE__ */ jsx(UISlotContext.Provider, { value: contextValue, children });
}
function useUISlots() {
  const context = useContext(UISlotContext);
  if (!context) {
    throw new Error(
      "useUISlots must be used within a UISlotProvider. Make sure your component tree is wrapped with <UISlotProvider>."
    );
  }
  return context;
}
function useSlotContent(slot) {
  const { getContent } = useUISlots();
  return getContent(slot);
}
function useSlotHasContent(slot) {
  const { hasContent } = useUISlots();
  return hasContent(slot);
}
var BUILT_IN_THEMES = [
  {
    name: "wireframe",
    displayName: "Wireframe",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "minimalist",
    displayName: "Minimalist",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "almadar",
    displayName: "Almadar",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "trait-wars",
    displayName: "Trait Wars",
    hasLightMode: false,
    hasDarkMode: true
  },
  // Extended themes
  {
    name: "ocean",
    displayName: "Ocean",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "forest",
    displayName: "Forest",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "sunset",
    displayName: "Sunset",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "lavender",
    displayName: "Lavender",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "rose",
    displayName: "Rose",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "slate",
    displayName: "Slate",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "ember",
    displayName: "Ember",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "midnight",
    displayName: "Midnight",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "sand",
    displayName: "Sand",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "neon",
    displayName: "Neon",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "arctic",
    displayName: "Arctic",
    hasLightMode: true,
    hasDarkMode: true
  },
  {
    name: "copper",
    displayName: "Copper",
    hasLightMode: true,
    hasDarkMode: true
  }
];
var ThemeContext = createContext(void 0);
var THEME_STORAGE_KEY = "theme";
var MODE_STORAGE_KEY = "theme-mode";
function getSystemMode() {
  if (typeof window === "undefined") return "light";
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
}
function resolveMode(mode) {
  if (mode === "system") {
    return getSystemMode();
  }
  return mode;
}
var ThemeProvider = ({
  children,
  themes = [],
  defaultTheme = "wireframe",
  defaultMode = "system",
  targetRef
}) => {
  const availableThemes = useMemo(() => {
    const themeMap = /* @__PURE__ */ new Map();
    BUILT_IN_THEMES.forEach((t) => themeMap.set(t.name, t));
    themes.forEach((t) => themeMap.set(t.name, t));
    return Array.from(themeMap.values());
  }, [themes]);
  const isScoped = !!targetRef;
  const [theme, setThemeState] = useState(() => {
    if (isScoped || typeof window === "undefined") return defaultTheme;
    const stored = localStorage.getItem(THEME_STORAGE_KEY);
    const validThemes = [
      ...BUILT_IN_THEMES.map((t) => t.name),
      ...themes.map((t) => t.name)
    ];
    if (stored && validThemes.includes(stored)) {
      return stored;
    }
    return defaultTheme;
  });
  const [mode, setModeState] = useState(() => {
    if (isScoped || typeof window === "undefined") return defaultMode;
    const stored = localStorage.getItem(MODE_STORAGE_KEY);
    if (stored === "light" || stored === "dark" || stored === "system") {
      return stored;
    }
    return defaultMode;
  });
  const [resolvedMode, setResolvedMode] = useState(
    () => resolveMode(mode)
  );
  const appliedTheme = useMemo(
    () => `${theme}-${resolvedMode}`,
    [theme, resolvedMode]
  );
  useEffect(() => {
    const updateResolved = () => {
      setResolvedMode(resolveMode(mode));
    };
    updateResolved();
    if (mode === "system") {
      const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
      const handleChange = () => updateResolved();
      mediaQuery.addEventListener("change", handleChange);
      return () => mediaQuery.removeEventListener("change", handleChange);
    }
    return void 0;
  }, [mode]);
  useEffect(() => {
    if (isScoped) {
      if (targetRef?.current) {
        targetRef.current.setAttribute("data-theme", appliedTheme);
        targetRef.current.classList.remove("light", "dark");
        targetRef.current.classList.add(resolvedMode);
      }
      return;
    }
    const root = document.documentElement;
    root.setAttribute("data-theme", appliedTheme);
    root.classList.remove("light", "dark");
    root.classList.add(resolvedMode);
  }, [appliedTheme, resolvedMode, targetRef, isScoped]);
  const setTheme = useCallback(
    (newTheme) => {
      const validTheme = availableThemes.find((t) => t.name === newTheme);
      if (validTheme) {
        setThemeState(newTheme);
        if (!isScoped && typeof window !== "undefined") {
          localStorage.setItem(THEME_STORAGE_KEY, newTheme);
        }
      } else {
        console.warn(
          `Theme "${newTheme}" not found. Available: ${availableThemes.map((t) => t.name).join(", ")}`
        );
      }
    },
    [availableThemes]
  );
  const setMode = useCallback((newMode) => {
    setModeState(newMode);
    if (!isScoped && typeof window !== "undefined") {
      localStorage.setItem(MODE_STORAGE_KEY, newMode);
    }
  }, []);
  const toggleMode = useCallback(() => {
    const newMode = resolvedMode === "dark" ? "light" : "dark";
    setMode(newMode);
  }, [resolvedMode, setMode]);
  const contextValue = useMemo(
    () => ({
      theme,
      mode,
      resolvedMode,
      setTheme,
      setMode,
      toggleMode,
      availableThemes,
      appliedTheme
    }),
    [
      theme,
      mode,
      resolvedMode,
      setTheme,
      setMode,
      toggleMode,
      availableThemes,
      appliedTheme
    ]
  );
  return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: contextValue, children });
};
function useTheme() {
  const context = useContext(ThemeContext);
  if (context === void 0) {
    return {
      theme: "wireframe",
      mode: "light",
      resolvedMode: "light",
      setTheme: () => {
      },
      setMode: () => {
      },
      toggleMode: () => {
      },
      availableThemes: BUILT_IN_THEMES,
      appliedTheme: "wireframe-light"
    };
  }
  return context;
}
var ThemeContext_default = ThemeContext;

// context/DesignThemeContext.tsx
var DesignThemeProvider = ThemeProvider;
function useDesignTheme() {
  const { theme, setTheme, availableThemes } = useTheme();
  return {
    designTheme: theme,
    setDesignTheme: setTheme,
    availableThemes: availableThemes.map((t) => t.name)
  };
}
var CurrentPagePathContext = createContext(void 0);
var CurrentPagePathProvider = ({
  value,
  children
}) => /* @__PURE__ */ jsx(CurrentPagePathContext.Provider, { value, children });
CurrentPagePathProvider.displayName = "CurrentPagePathProvider";
var useCurrentPagePath = () => useContext(CurrentPagePathContext);
var ANONYMOUS_USER = {
  id: "anonymous",
  role: "anonymous",
  permissions: []
};
var UserContext = createContext(null);
function UserProvider({
  user = null,
  children
}) {
  const hasRole = useCallback(
    (role) => {
      if (!user) return role === "anonymous";
      return user.role === role;
    },
    [user]
  );
  const hasPermission = useCallback(
    (permission) => {
      if (!user) return false;
      return user.permissions?.includes(permission) ?? false;
    },
    [user]
  );
  const hasAnyRole = useCallback(
    (roles) => {
      if (!user) return roles.includes("anonymous");
      return user.role ? roles.includes(user.role) : false;
    },
    [user]
  );
  const hasAllPermissions = useCallback(
    (permissions) => {
      if (!user || !user.permissions) return false;
      return permissions.every((p) => user.permissions?.includes(p));
    },
    [user]
  );
  const getUserField = useCallback(
    (path) => {
      const userData = user ?? ANONYMOUS_USER;
      const parts = path.split(".");
      let value = userData;
      for (const segment of parts) {
        if (value === null || value === void 0) {
          return void 0;
        }
        if (typeof value === "object") {
          value = value[segment];
        } else {
          return void 0;
        }
      }
      return value;
    },
    [user]
  );
  const contextValue = useMemo(
    () => ({
      user,
      isLoggedIn: user !== null,
      hasRole,
      hasPermission,
      hasAnyRole,
      hasAllPermissions,
      getUserField
    }),
    [user, hasRole, hasPermission, hasAnyRole, hasAllPermissions, getUserField]
  );
  return /* @__PURE__ */ jsx(UserContext.Provider, { value: contextValue, children });
}
function useUser() {
  const context = useContext(UserContext);
  if (!context) {
    return {
      user: null,
      isLoggedIn: false,
      hasRole: (role) => role === "anonymous",
      hasPermission: () => false,
      hasAnyRole: (roles) => roles.includes("anonymous"),
      hasAllPermissions: () => false,
      getUserField: () => void 0
    };
  }
  return context;
}
function useHasRole(role) {
  const { hasRole } = useUser();
  return hasRole(role);
}
function useHasPermission(permission) {
  const { hasPermission } = useUser();
  return hasPermission(permission);
}
function useUserForEvaluation() {
  const { user, isLoggedIn } = useUser();
  return isLoggedIn && user ? user : void 0;
}

export { ANONYMOUS_USER, BUILT_IN_THEMES, CurrentPagePathContext, CurrentPagePathProvider, DesignThemeProvider, ThemeContext_default as ThemeContext, ThemeProvider, UISlotContext, UISlotProvider, UserContext, UserProvider, useCurrentPagePath, useDesignTheme, useHasPermission, useHasRole, useSlotContent, useSlotHasContent, useTheme, useUISlots, useUser, useUserForEvaluation };
