import { Emitter } from 'mitt';
import * as react$1 from 'react';
import react__default, { ReactNode } from 'react';
import * as react_jsx_runtime from 'react/jsx-runtime';

type CBListener = () => void;
interface CBStore {
    getState: () => CBState;
    dispatch: (action: CBAction) => void;
    subscribe: (listener: CBListener) => () => void;
}
type CBAgentID = string;
interface CBAgent {
    id: CBAgentID;
    name: string;
    face?: string;
    designation?: string;
    description?: string;
    introduction?: string;
    isActive: boolean;
    isAvailable: boolean;
    isBusy: boolean;
}
type CBTaskStatus = 'idle' | 'ongoing' | 'completed' | 'failed';
type CBBlockProcessor = 'TEXT' | 'JSON';
interface CBTagConfig {
    tag: string;
    processor: CBBlockProcessor;
    component: React.ComponentType<{
        ai: any;
    }>;
}
interface CBMessageBlock {
    id: string;
    tag: string;
    taskId: string;
    content: any;
    createdAt: number;
    component: React.ComponentType<{
        ai: any;
    }>;
}
interface CBTask {
    id: string;
    agentId: CBAgentID;
    input: string;
    status: CBTaskStatus;
    createdAt: number;
    updatedAt: number;
    meta?: Record<string, any>;
    response?: string;
    messageBlocks?: CBMessageBlock[];
}
interface CBState {
    agents: CBAgent[];
    tasks: CBTask[];
}
type CBAction = {
    type: 'ADD_AGENT';
    payload: CBAgent;
} | {
    type: 'UPDATE_AGENT';
    payload: Partial<CBAgent> & {
        id: CBAgentID;
    };
} | {
    type: 'ADD_TASK';
    payload: CBTask;
} | {
    type: 'UPDATE_TASK';
    payload: Partial<CBTask> & {
        id: string;
    };
} | {
    type: 'REMOVE_TASK';
    payload: {
        id: string;
    };
} | {
    type: 'ADD_MESSAGE_BLOCK';
    payload: {
        taskId: string;
        block: CBMessageBlock;
    };
};
type CBBlockCallback<T = any> = (block: T) => void;
type CBTaskCallbacks = {
    [blockTag: string]: CBBlockCallback<any>;
} & {
    onComplete?: () => void;
    onError?: (error: string) => void;
};
type CBStartTaskParams = {
    agentId: CBAgentID;
    input: string;
    callbacks: CBTaskCallbacks;
    meta?: Record<string, any>;
};

declare function CBAgentReducer$1(state: CBState | undefined, action: CBAction): CBState;
declare const addAgent$1: (agent: CBAgent) => CBAction;
declare const updateAgent$1: (agent: Partial<CBAgent> & {
    id: string;
}) => CBAction;
declare const addTask$1: (task: CBTask) => CBAction;
declare const updateTask$1: (task: Partial<CBTask> & {
    id: string;
}) => CBAction;
declare const removeTask$1: (id: string) => CBAction;
declare const addMessageBlock$1: (taskId: string, block: CBMessageBlock) => CBAction;
declare const getTasksForAgent$1: (state: CBState, agentId: string) => CBTask[];

type CBBlockSupervisorCallbacks = {
    onBlockFound?: (tag: string) => void;
    onBlockProcessed?: (block: CBMessageBlock) => void;
    onComplete?: () => void;
    onError?: (err: string) => void;
};
declare function createAgentSupervisor$1({ callbacks, tagConfigs, emitter, }: {
    callbacks: CBBlockSupervisorCallbacks;
    tagConfigs: CBTagConfig[];
    emitter?: Emitter<any>;
}): {
    getStatus: () => CBTaskStatus;
    startTask: (taskId: string) => void;
    parseChunk: (chunk: string) => void;
    complete: () => void;
    error: (err: string) => void;
    reset: () => void;
};

declare function getTask$1(tasks: CBTask[], id: string): CBTask | undefined;
declare function setTaskStatus$1(tasks: CBTask[], id: string, status: CBTaskStatus): CBTask[];

declare function createCBStore$1(reducer: (state: CBState, action: CBAction) => CBState, preloadedState: CBState): CBStore;

declare function useCBTaskManager$1(): {
    tasks: CBTask[];
    createTask: (agentId: string, input: string, meta?: Record<string, any>) => string;
    updateTask: (id: string, updates: Partial<CBTask>) => void;
    removeTask: (id: string) => void;
    getTask: (id: string) => CBTask | undefined;
    setTaskStatus: (id: string, status: CBTaskStatus) => void;
    addMessageBlockToTask: (taskId: string, block: CBMessageBlock) => void;
};

var nanoid = require('nanoid');
var mitt = require('mitt');
var react = require('react');
var jsxRuntime = require('react/jsx-runtime');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var mitt__default = /*#__PURE__*/_interopDefault(mitt);

// cranberrry - AI Agentic UI Framework For Frontend
// https://github.com/Ritvyk/cranberrry


// core/agentSlice.ts
var initialState = {
  agents: [],
  tasks: []
};
function CBAgentReducer(state = initialState, action) {
  switch (action.type) {
    case "ADD_AGENT":
      return {
        ...state,
        agents: [...state.agents, action.payload]
      };
    case "UPDATE_AGENT":
      return {
        ...state,
        agents: state.agents.map(
          (agent) => agent.id === action.payload.id ? { ...agent, ...action.payload } : agent
        )
      };
    case "ADD_TASK":
      return {
        ...state,
        tasks: [...state.tasks, action.payload]
      };
    case "UPDATE_TASK":
      return {
        ...state,
        tasks: state.tasks.map(
          (task) => task.id === action.payload.id ? { ...task, ...action.payload } : task
        )
      };
    case "REMOVE_TASK":
      return {
        ...state,
        tasks: state.tasks.filter((task) => task.id !== action.payload.id)
      };
    case "ADD_MESSAGE_BLOCK":
      return {
        ...state,
        tasks: state.tasks.map(
          (task) => task.id === action.payload.taskId ? { ...task, messageBlocks: [...task.messageBlocks || [], action.payload.block] } : task
        )
      };
    default:
      return state;
  }
}
var addAgent = (agent) => ({
  type: "ADD_AGENT",
  payload: agent
});
var updateAgent = (agent) => ({
  type: "UPDATE_AGENT",
  payload: agent
});
var addTask = (task) => ({
  type: "ADD_TASK",
  payload: task
});
var updateTask = (task) => ({
  type: "UPDATE_TASK",
  payload: task
});
var removeTask = (id) => ({
  type: "REMOVE_TASK",
  payload: { id }
});
var addMessageBlock = (taskId, block) => ({
  type: "ADD_MESSAGE_BLOCK",
  payload: { taskId, block }
});
var getTasksForAgent = (state, agentId) => {
  return state.tasks.filter((task) => task.agentId === agentId);
};
var globalEmitter = typeof window !== "undefined" ? window.__cranberrryEmitter || (window.__cranberrryEmitter = mitt__default.default()) : mitt__default.default();
function createAgentSupervisor({
  callbacks,
  tagConfigs,
  emitter = globalEmitter
}) {
  let status = "idle";
  let buffer = "";
  let currentTaskId = "";
  let openTagPositions = [];
  function getStatus() {
    return status;
  }
  function startTask(taskId) {
    status = "ongoing";
    buffer = "";
    openTagPositions = [];
    currentTaskId = taskId;
  }
  function parseChunk(chunk) {
    if (status !== "ongoing") return;
    buffer += chunk;
    let foundBlock = false;
    for (const tagConfig of tagConfigs) {
      const { tag, processor, component } = tagConfig;
      const openingTagRegex = new RegExp(`<${tag}>`, "g");
      let match;
      while ((match = openingTagRegex.exec(buffer)) !== null) {
        if (!openTagPositions.some((t) => t.tag === tag && t.index === match.index)) {
          openTagPositions.push({ tag, index: match.index });
          callbacks.onBlockFound?.(tag);
        }
      }
      const blockRegex = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "g");
      while ((match = blockRegex.exec(buffer)) !== null) {
        let rawContent = match[1];
        let content = rawContent;
        if (processor === "JSON") {
          try {
            content = JSON.parse(rawContent);
          } catch {
            content = rawContent;
          }
        }
        const block = {
          id: nanoid.nanoid(),
          tag,
          content,
          createdAt: Date.now(),
          component,
          taskId: currentTaskId
        };
        callbacks.onBlockProcessed?.(block);
        emitter.emit("message", { taskId: currentTaskId, block });
        buffer = buffer.slice(0, match.index) + buffer.slice(match.index + match[0].length);
        openTagPositions = openTagPositions.filter((t) => !(t.tag === tag && t.index === match.index));
        blockRegex.lastIndex = 0;
        foundBlock = true;
      }
    }
    if (foundBlock) {
      parseChunk("");
    } else if (chunk === "" && buffer === "" && status === "ongoing") {
      status = "completed";
      callbacks.onComplete?.();
    }
  }
  function complete() {
    status = "completed";
    callbacks.onComplete?.();
  }
  function error(err) {
    status = "failed";
    callbacks.onError?.(err);
  }
  function reset() {
    status = "idle";
    buffer = "";
    openTagPositions = [];
  }
  return {
    getStatus,
    startTask,
    parseChunk,
    complete,
    error,
    reset
  };
}

// core/agentTaskManager.ts
function getTask(tasks, id) {
  return tasks.find((task) => task.id === id);
}
function setTaskStatus(tasks, id, status) {
  return tasks.map((task) => task.id === id ? { ...task, status } : task);
}

// core/store.ts
function createCBStore(reducer, preloadedState) {
  let state = preloadedState;
  let listeners = [];
  function getState() {
    return state;
  }
  function dispatch(action) {
    state = reducer(state, action);
    listeners.forEach((listener) => listener());
  }
  function subscribe(listener) {
    listeners.push(listener);
    return () => {
      const index = listeners.indexOf(listener);
      if (index > -1) listeners.splice(index, 1);
    };
  }
  return {
    getState,
    dispatch,
    subscribe
  };
}
var CranberrryStoreContext = react.createContext(null);
CranberrryStoreContext.displayName = "CranberrryStoreContext";
function CranberrryProvider$1({
  store,
  children
}) {
  return /* @__PURE__ */ jsxRuntime.jsx(CranberrryStoreContext.Provider, { value: store, children });
}
function useCranberrryStore$1() {
  const store = react.useContext(CranberrryStoreContext);
  if (!store) {
    throw new Error("useCranberrryStore must be used within a CranberrryProvider");
  }
  return store;
}

// hooks/useAgentDispatch.ts
function useCBDispatch$1() {
  return useCranberrryStore$1().dispatch;
}
function useCBSelector$1(selector) {
  const store = useCranberrryStore$1();
  const [selected, setSelected] = react.useState(() => selector(store.getState()));
  const latestSelected = react.useRef(selected);
  react.useEffect(() => {
    function checkForUpdates() {
      const newSelected = selector(store.getState());
      if (newSelected !== latestSelected.current) {
        latestSelected.current = newSelected;
        setSelected(newSelected);
      }
    }
    const unsubscribe = store.subscribe(checkForUpdates);
    return unsubscribe;
  }, [store, selector]);
  return selected;
}
var useAgentSelector$1 = useCBSelector$1;

// hooks/useAgentTaskManager.ts
function useCBTaskManager() {
  const dispatch = useCBDispatch$1();
  const tasks = useCBSelector$1((state) => state.tasks);
  const createTask = react.useCallback((agentId, input, meta) => {
    const id = Math.random().toString(36).substr(2, 9);
    const now = Date.now();
    dispatch(
      addTask({
        id,
        agentId,
        input,
        status: "ongoing",
        createdAt: now,
        updatedAt: now,
        meta
      })
    );
    return id;
  }, [dispatch]);
  const updateTask2 = react.useCallback((id, updates) => {
    dispatch(updateTask({ id, ...updates }));
  }, [dispatch]);
  const removeTask2 = react.useCallback((id) => {
    dispatch(removeTask(id));
  }, [dispatch]);
  const getTask2 = react.useCallback((id) => {
    return tasks.find((task) => task.id === id);
  }, [tasks]);
  const setTaskStatus2 = react.useCallback((id, status) => {
    dispatch(updateTask({ id, status, updatedAt: Date.now() }));
  }, [dispatch]);
  const addMessageBlockToTask = react.useCallback((taskId, block) => {
    dispatch(addMessageBlock(taskId, block));
  }, [dispatch]);
  return {
    tasks,
    createTask,
    updateTask: updateTask2,
    removeTask: removeTask2,
    getTask: getTask2,
    setTaskStatus: setTaskStatus2,
    addMessageBlockToTask
  };
}

// hooks/useAIAgent.ts
function useCBAgent$1() {
  const agents = useCBSelector$1((state) => state.agents);
  const getAgentById = (id) => agents.find((agent) => agent.id === id);
  return { agents, getAgentById };
}
var globalEmitter2 = typeof window !== "undefined" ? window.__cranberrryEmitter || (window.__cranberrryEmitter = mitt__default.default()) : mitt__default.default();
function useCBTaskSupervisor$1({
  callbacks,
  tagConfigs,
  emitter = globalEmitter2
}) {
  const supervisorRef = react.useRef(null);
  const [status, setStatus] = react.useState("idle");
  const [error, setError] = react.useState(null);
  if (!supervisorRef.current) {
    supervisorRef.current = createAgentSupervisor({ callbacks, tagConfigs, emitter });
  }
  const startTask = react.useCallback((taskId) => {
    supervisorRef.current?.startTask(taskId);
    setStatus("ongoing");
    setError(null);
  }, []);
  const parseChunk = react.useCallback((chunk) => {
    supervisorRef.current?.parseChunk(chunk);
  }, []);
  const complete = react.useCallback(() => {
    supervisorRef.current?.complete();
    setStatus("completed");
  }, []);
  const errorCallback = react.useCallback((err) => {
    supervisorRef.current?.error(err);
    setStatus("failed");
    setError(err);
  }, []);
  const reset = react.useCallback(() => {
    supervisorRef.current?.reset();
    setStatus("idle");
    setError(null);
  }, []);
  return {
    status,
    startTask,
    parseChunk,
    complete,
    error,
    errorCallback,
    reset
  };
}
var globalEmitter3 = typeof window !== "undefined" ? window.__cranberrryEmitter || (window.__cranberrryEmitter = mitt__default.default()) : mitt__default.default();
function useCBController$1({
  agentId,
  tagConfigs,
  callbacks
}) {
  const [prompt, setPrompt] = react.useState("");
  const [errorMessage, setErrorMessage] = react.useState(null);
  const [currentTaskId, setCurrentTaskId] = react.useState(null);
  const currentTaskIdRef = react.useRef(null);
  const dispatch = useCBDispatch$1();
  const emitter = globalEmitter3;
  const {
    tasks,
    createTask,
    updateTask: updateTask2,
    removeTask: removeTask2,
    getTask: getTask2,
    setTaskStatus: setTaskStatus2,
    addMessageBlockToTask
    // addMessageBlock, getMessageBlocks imported above
  } = useCBTaskManager();
  currentTaskIdRef.current = currentTaskId;
  const wrappedCallbacks = {
    ...callbacks,
    onComplete: () => {
      if (currentTaskIdRef.current) {
        updateTask2(currentTaskIdRef.current, { status: "completed", updatedAt: Date.now() });
      }
      dispatch(updateAgent({ id: agentId, isBusy: false }));
      callbacks.onComplete?.();
    },
    onError: (err) => {
      if (currentTaskIdRef.current) {
        updateTask2(currentTaskIdRef.current, { status: "failed", updatedAt: Date.now() });
      }
      dispatch(updateAgent({ id: agentId, isBusy: false }));
      callbacks.onError?.(err);
    }
  };
  const [messageBlocks, setMessageBlocks] = react.useState([]);
  react.useEffect(() => {
    if (currentTaskId) {
      setMessageBlocks(getTask2(currentTaskId)?.messageBlocks || []);
    } else {
      setMessageBlocks([]);
    }
  }, [currentTaskId, tasks]);
  const supervisor = useCBTaskSupervisor$1({
    callbacks: {
      ...wrappedCallbacks,
      onBlockProcessed: (block) => {
        if (currentTaskIdRef.current) {
          addMessageBlockToTask(currentTaskIdRef.current, block);
        }
        callbacks.onBlockProcessed?.(block);
      },
      onBlockFound: (tag) => {
        callbacks.onBlockFound?.(tag);
      }
    },
    tagConfigs,
    emitter
  });
  const { status, startTask, parseChunk, complete, error: supervisorError, errorCallback, reset } = supervisor;
  const isRunning = status === "ongoing";
  const startAgentTask = react.useCallback(
    (newPrompt, newMeta) => {
      if (!newPrompt) throw new Error("Prompt is required");
      setPrompt(newPrompt);
      setErrorMessage(null);
      const newTaskId = createTask(agentId, newPrompt, newMeta);
      setCurrentTaskId(newTaskId);
      currentTaskIdRef.current = newTaskId;
      dispatch(updateAgent({ id: agentId, isBusy: true }));
      startTask(newTaskId);
      return newTaskId;
    },
    [startTask, createTask, tagConfigs, agentId, dispatch]
  );
  const startExistingAgentTask = react.useCallback(
    (taskId) => {
      const existingTask = getTask2(taskId);
      if (!existingTask) {
        throw new Error(`Task with ID ${taskId} not found`);
      }
      if (existingTask.agentId !== agentId) {
        throw new Error(`Task ${taskId} does not belong to agent ${agentId}`);
      }
      if (existingTask.status === "completed") {
        throw new Error(`Task ${taskId} is already completed and cannot be resumed`);
      }
      if (existingTask.status === "failed") {
        updateTask2(taskId, { status: "ongoing", updatedAt: Date.now() });
      }
      setPrompt(existingTask.input);
      setErrorMessage(null);
      setCurrentTaskId(taskId);
      currentTaskIdRef.current = taskId;
      dispatch(updateAgent({ id: agentId, isBusy: true }));
      startTask(taskId);
      return taskId;
    },
    [getTask2, agentId, updateTask2, startTask, dispatch]
  );
  const completeWithError = react.useCallback((err) => {
    setErrorMessage(err);
    callbacks.onError?.(err);
    errorCallback(err);
  }, [callbacks, errorCallback]);
  return {
    prompt,
    setPrompt,
    isRunning,
    error: errorMessage || supervisorError,
    startAgentTask,
    startExistingAgentTask,
    parseChunk,
    complete,
    reset,
    status,
    tasks,
    updateTask: updateTask2,
    removeTask: removeTask2,
    getTask: getTask2,
    setTaskStatus: setTaskStatus2,
    completeWithError,
    messageBlocks,
    emitter
  };
}
var globalEmitter4 = typeof window !== "undefined" ? window.__cranberrryEmitter || (window.__cranberrryEmitter = mitt__default.default()) : mitt__default.default();
var CranberrryRenderer$1 = ({ taskId }) => {
  const messageBlocks = useAgentSelector$1(
    (state) => state.tasks.find((t) => t.id === taskId)?.messageBlocks || []
  );
  const [liveBlocks, setLiveBlocks] = react.useState(messageBlocks);
  react.useEffect(() => {
    setLiveBlocks(messageBlocks);
  }, [messageBlocks]);
  react.useEffect(() => {
    function onMessage({ taskId: incomingTaskId, block }) {
      if (incomingTaskId === taskId) {
        setLiveBlocks((prev) => [...prev, block]);
      }
    }
    globalEmitter4.on("message", onMessage);
    return () => {
      globalEmitter4.off("message", onMessage);
    };
  }, [taskId]);
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cranberrry-renderer-messages space-y-2", children: liveBlocks.map((block) => {
    const BlockComponent = block.component;
    return /* @__PURE__ */ jsxRuntime.jsx(BlockComponent, { ai: block.content }, block.id);
  }) });
};

exports.CBAgentReducer = CBAgentReducer;
exports.CranberrryProvider = CranberrryProvider$1;
exports.CranberrryRenderer = CranberrryRenderer$1;
exports.addAgent = addAgent;
exports.addMessageBlock = addMessageBlock;
exports.addTask = addTask;
exports.createAgentSupervisor = createAgentSupervisor;
exports.createCBStore = createCBStore;
exports.getTask = getTask;
exports.getTasksForAgent = getTasksForAgent;
exports.removeTask = removeTask;
exports.setTaskStatus = setTaskStatus;
exports.updateAgent = updateAgent;
exports.updateTask = updateTask;
exports.useAgentSelector = useAgentSelector$1;
exports.useCBAgent = useCBAgent$1;
exports.useCBController = useCBController$1;
exports.useCBDispatch = useCBDispatch$1;
exports.useCBSelector = useCBSelector$1;
exports.useCBTaskManager = useCBTaskManager;
exports.useCBTaskSupervisor = useCBTaskSupervisor$1;
exports.useCranberrryStore = useCranberrryStore$1;

declare function useCBDispatch(): (action: undefined) => void;

declare function useCBSelector<T>(selector: (state: CBState) => T): T;
declare const useAgentSelector: typeof useCBSelector;

declare function useCBAgent(): {
    agents: CBAgent[];
    getAgentById: (id: string) => CBAgent | undefined;
};

declare function useCBController({ agentId, tagConfigs, callbacks, }: {
    agentId: string;
    tagConfigs: CBTagConfig[];
    callbacks: CBBlockSupervisorCallbacks;
}): {
    prompt: string;
    setPrompt: react$1.Dispatch<react$1.SetStateAction<string>>;
    isRunning: boolean;
    error: string | null;
    startAgentTask: (newPrompt: string, newMeta?: Record<string, any>) => string;
    startExistingAgentTask: (taskId: string) => string;
    parseChunk: (chunk: string) => void;
    complete: () => void;
    reset: () => void;
    status: undefined;
    tasks: undefined[];
    updateTask: (id: string, updates: Partial<undefined>) => void;
    removeTask: (id: string) => void;
    getTask: (id: string) => undefined | undefined;
    setTaskStatus: (id: string, status: undefined) => void;
    completeWithError: (err: string) => void;
    messageBlocks: CBMessageBlock[];
    emitter: Emitter<any>;
};

declare function useCBTaskSupervisor({ callbacks, tagConfigs, emitter, }: {
    callbacks: CBBlockSupervisorCallbacks;
    tagConfigs: CBTagConfig[];
    emitter?: Emitter<any>;
}): {
    status: CBTaskStatus;
    startTask: (taskId: string) => void;
    parseChunk: (chunk: string) => void;
    complete: () => void;
    error: string | null;
    errorCallback: (err: string) => void;
    reset: () => void;
};

declare function CranberrryProvider({ store, children, }: {
    store: CBStore;
    children: ReactNode;
}): react_jsx_runtime.JSX.Element;
declare function useCranberrryStore(): CBStore;

interface CranberrryRendererProps {
    taskId: string;
}
declare const CranberrryRenderer: react__default.FC<CranberrryRendererProps>;

export { type CBAction, type CBAgent, type CBAgentID, CBAgentReducer$1 as CBAgentReducer, type CBBlockCallback, type CBBlockProcessor, type CBBlockSupervisorCallbacks, type CBListener, type CBMessageBlock, type CBStartTaskParams, type CBState, type CBStore, type CBTagConfig, type CBTask, type CBTaskCallbacks, type CBTaskStatus, CranberrryProvider, CranberrryRenderer, addAgent$1 as addAgent, addMessageBlock$1 as addMessageBlock, addTask$1 as addTask, createAgentSupervisor$1 as createAgentSupervisor, createCBStore$1 as createCBStore, getTask$1 as getTask, getTasksForAgent$1 as getTasksForAgent, removeTask$1 as removeTask, setTaskStatus$1 as setTaskStatus, updateAgent$1 as updateAgent, updateTask$1 as updateTask, useAgentSelector, useCBAgent, useCBController, useCBDispatch, useCBSelector, useCBTaskManager$1 as useCBTaskManager, useCBTaskSupervisor, useCranberrryStore };
