import React, { forwardRef, useEffect, useMemo, useRef, type ForwardedRef } from 'react';

import { MixpanelProvider } from '../../analytics/mixpanelContext';
import { SuperagentThemeProvider } from './SuperagentScreen';
import { UserProvider } from '../../user/userContext';
import { routeIdentityKey, shouldNavigateHostBack } from '../../runtime/routeKey';
import { SuperagentRuntimeProvider, type SuperagentRuntimeContextValue } from '../../runtime/runtimeContext';
import { SuperagentHomeScreenView } from './SuperagentHomeScreenView';
import { useSuperagentRuntime } from '../../runtime/useSuperagentRuntime';
import { useSuperagentAttachmentPicker } from '../attachments/useSuperagentAttachmentPicker';
import type { SuperagentHomeScreenHandle, SuperagentHomeScreenProps } from '../../types';

/**
 * Public entry point for the Superagent mobile experience.
 *
 * The shell owns everything the package can produce itself: it runs
 * `useSuperagentRuntime` (agents, channels, connectors, automations, secrets,
 * files, the API + realtime clients, and every mutation handler) and the
 * attachment picker, publishes them through `SuperagentRuntimeProvider`, and
 * renders the pure `SuperagentHomeScreenView` inside the theme + user + Mixpanel
 * providers. Descendants read what they need via the `useSuperagent*` domain hooks
 * rather than receiving drilled props. The host supplies only what it alone can:
 * the auth-backed `session`, the signed-in `user`, the build `environment`, native
 * `adapters`, and app-shell navigation wiring.
 */
export const SuperagentHomeScreen = forwardRef<SuperagentHomeScreenHandle, SuperagentHomeScreenProps>(
  function SuperagentHomeScreen(props, ref) {
    // Mount the providers here — above the runtime — so `useSuperagentRuntime`
    // (and its mutation handlers) run inside `MixpanelProvider` and can report BI
    // events from their success branches via `useAgentBi()`.
    return (
      <SuperagentThemeProvider defaultColorScheme={props.defaultColorScheme} onColorSchemeChange={props.onColorSchemeChange}>
        <UserProvider user={props.user}>
          <MixpanelProvider
            distinctId={props.user?.id ?? null}
            environment={props.environment ?? 'production'}
            superProperties={{
              tier: props.user?.subscription_pricing_tier ?? props.user?.subscription_tier ?? 'free',
              feature_flags: props.user?.feature_flags ?? [],
            }}
          >
            <SuperagentHomeScreenContent {...props} forwardedRef={ref} />
          </MixpanelProvider>
        </UserProvider>
      </SuperagentThemeProvider>
    );
  },
);

function SuperagentHomeScreenContent(
  {
    session,
    user,
    environment = 'production',
    adapters,
    navigationMode,
    initialRoute,
    isActive,
    onOpenAgent,
    onAgentBack,
    onRouteChange,
    onActiveAgentChange,
    hideConversationHeader,
    contentTopInset,
    onViewPlans,
    forwardedRef,
  }: SuperagentHomeScreenProps & { forwardedRef: ForwardedRef<SuperagentHomeScreenHandle> },
) {
    const runtime = useSuperagentRuntime({ session, user, adapters, initialRoute });

    // Attachment picking is a native capability: wire it only when the host
    // provided the adapters, otherwise the composer hides those affordances.
    const pickerInput = useMemo(
      () =>
        adapters?.attachments
          ? { baseUrl: session.baseUrl, getAccessToken: session.getAccessToken, nativeAdapters: adapters.attachments }
          : undefined,
      [adapters?.attachments, session.baseUrl, session.getAccessToken],
    );
    const picker = useSuperagentAttachmentPicker(pickerInput);

    // Surface the resolved active agent (including once its details load) so a
    // host-owned native nav bar can set its title. Reports null while on the home
    // list so the title doesn't linger on the default first agent.
    const titleAgent = runtime.currentRoute.name === 'agent' ? runtime.activeAgent : null;
    useEffect(() => {
      onActiveAgentChange?.(titleAgent);
    }, [titleAgent, onActiveAgentChange]);

    // Notify the host of every route change from the one place that sees them all:
    // the runtime's own `currentRoute`. This covers both view-driven navigation
    // (which flows through `runtime.onRouteChange`) and runtime-driven moves the
    // host never asked for — e.g. deleting the active agent snaps back to home — so
    // a host toggling bottom tabs on the home route stays in sync either way. Keyed
    // on the route identity (not the object/callback) and skipping mount so the host
    // isn't re-told the route it just supplied.
    const currentRouteKey = routeIdentityKey(runtime.currentRoute);
    const routeNotifyMountedRef = useRef(false);
    useEffect(() => {
      if (!routeNotifyMountedRef.current) {
        routeNotifyMountedRef.current = true;
        return;
      }
      onRouteChange?.(runtime.currentRoute);
      if (shouldNavigateHostBack(runtime.currentRoute, onAgentBack != null)) {
        onAgentBack?.();
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [currentRouteKey]);

    // The single value published to the whole screen tree. Runtime data/handlers,
    // plus the shell-owned overrides (host navigation, media pickers, plans CTA,
    // debug flag derived from the build flavor, content inset, tab-active flag).
    const runtimeValue: SuperagentRuntimeContextValue = {
      ...runtime,
      navigationMode,
      // Forward the runtime's own route (seeded from the host `initialRoute` prop),
      // so runtime-driven navigation — delete → home, create → new agent — reaches
      // the view instead of being pinned to the static host prop.
      initialRoute: runtime.currentRoute,
      onOpenAgent: onOpenAgent ?? runtime.onOpenAgent,
      onAgentBack,
      // View navigation drives the runtime only; the host is notified via the
      // effect above (which also catches runtime-driven route changes).
      onRouteChange: runtime.onRouteChange,
      onViewPlans,
      showDebugPayloads: environment !== 'production',
      isActive,
      contentTopInset,
      hideConversationHeader,
      onPickFiles: picker.onPickFiles,
      onPickPhotos: picker.onPickPhotos,
      onTakePhoto: picker.onTakePhoto,
    };

    return (
      <SuperagentRuntimeProvider value={runtimeValue}>
        <SuperagentHomeScreenView handleRef={forwardedRef} />
        {picker.attachmentPickerModal}
      </SuperagentRuntimeProvider>
    );
}
