'use client';

import {createContext, useCallback, useContext, useMemo, useState} from 'react';

/**
 * All Copilot state lives here, and this provider is mounted in
 * app/providers.tsx — ABOVE the route tree.
 *
 * Two things force that placement:
 *  1. Route changes. The panel itself sits in (workspace)/layout.tsx, which the
 *     App Router preserves across sibling navigations, so it would survive
 *     /dashboard → /staff on its own.
 *  2. The tablet breakpoint. Crossing it swaps the inline LayoutPanel for a
 *     slide-over, which genuinely unmounts the panel. Holding state up here
 *     means presentation can change without losing a half-typed message.
 *
 * The panel is a pure view over this context. Nothing below it owns state.
 */

export type CopilotTab = 'ai' | 'analytics' | 'chat';

export interface ChatMessage {
  id: string;
  sender: 'user' | 'assistant';
  text: string;
  at: string;
}

interface CopilotValue {
  tab: CopilotTab;
  setTab: (t: CopilotTab) => void;
  isOpen: boolean;
  setIsOpen: (v: boolean) => void;
  toggle: () => void;
  /** Slide-over visibility, used below the laptop breakpoint. */
  isSlideOverOpen: boolean;
  setSlideOverOpen: (v: boolean) => void;
  messages: ChatMessage[];
  /** The in-progress composer value. Kept here so navigation never drops it. */
  draft: string;
  setDraft: (v: string) => void;
  send: (text: string) => void;
  isStreaming: boolean;
}

const CopilotContext = createContext<CopilotValue | null>(null);

export function CopilotProvider({children}: {children: React.ReactNode}) {
  const [tab, setTab] = useState<CopilotTab>('ai');
  const [isOpen, setIsOpen] = useState(true);
  const [isSlideOverOpen, setSlideOverOpen] = useState(false);
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [draft, setDraft] = useState('');
  const [isStreaming] = useState(false);

  const send = useCallback((text: string) => {
    const trimmed = text.trim();
    if (!trimmed) return;
    setMessages((prev) => [
      ...prev,
      {
        id: `m${prev.length + 1}`,
        sender: 'user',
        text: trimmed,
        // Timestamps are assigned on send (a user event), never during render —
        // Date.now() in a render path is a hydration mismatch waiting to happen.
        at: new Date().toISOString(),
      },
    ]);
    setDraft('');
  }, []);

  const toggle = useCallback(() => setIsOpen((v) => !v), []);

  const value = useMemo(
    () => ({
      tab,
      setTab,
      isOpen,
      setIsOpen,
      toggle,
      isSlideOverOpen,
      setSlideOverOpen,
      messages,
      draft,
      setDraft,
      send,
      isStreaming,
    }),
    [tab, isOpen, isSlideOverOpen, messages, draft, send, toggle, isStreaming],
  );

  return <CopilotContext value={value}>{children}</CopilotContext>;
}

export function useCopilot(): CopilotValue {
  const ctx = useContext(CopilotContext);
  if (!ctx) {
    throw new Error('useCopilot must be used inside <CopilotProvider>');
  }
  return ctx;
}
