import React, { useCallback, useMemo, useState, type ReactNode } from 'react';
import { View, type StyleProp, type ViewStyle } from 'react-native';

import {
  createThemedStyles,
  SuperagentThemeContext,
  syncSuperagentColorScheme,
  type SuperagentColorScheme,
} from '../../theme';

/**
 * Reusable design-system shell for every Superagent native screen.
 *
 * The DS theming layer (theme.ts/tokens.ts + `createThemedStyles`) only resolves
 * colors correctly when the active color scheme has been published to the
 * module-level resolver and exposed via context. Rather than re-wire that on each
 * screen, screens compose these two pieces:
 *
 *  - `SuperagentThemeProvider` — the theming ROOT. Owns the active scheme, syncs
 *    it during render (so the whole subtree resolves to the right DS scheme), and
 *    exposes it via context. Mount once near the top of a screen tree.
 *  - `SuperagentScreen` — the themed SURFACE. A full-bleed container painted with
 *    the DS canvas token. Nested screens (rendered under an existing provider)
 *    just use this; a standalone screen can pass `colorScheme` (controlled) or
 *    `defaultColorScheme` (uncontrolled) to have it set up the provider too.
 *
 * Safe-area insets stay the screen's concern (e.g. SuperagentTopBar pads the
 * status bar itself), so this surface is intentionally edge-to-edge.
 */

const shellStyles = createThemedStyles({
  // #000000 → surface.canvas (DS): stone-50 in light, neutral-950 in dark.
  screen: { backgroundColor: '#000000', flex: 1 },
});

interface SuperagentThemeProviderProps {
  /**
   * Controlled active scheme: when provided, the host owns it. It's read directly
   * during render (no stale first paint) and an in-tree `setScheme` only notifies
   * via `onColorSchemeChange` — it never mutates local state, so context and the
   * module-level scheme can't diverge from the prop.
   */
  colorScheme?: SuperagentColorScheme;
  /** Uncontrolled initial scheme (default 'light'); an in-app `setScheme` owns it after. */
  defaultColorScheme?: SuperagentColorScheme;
  /** Notified whenever the scheme changes (in-tree toggle); required for the controlled mode. */
  onColorSchemeChange?: (scheme: SuperagentColorScheme) => void;
  children: ReactNode;
}

export function SuperagentThemeProvider({
  colorScheme,
  defaultColorScheme,
  onColorSchemeChange,
  children,
}: SuperagentThemeProviderProps) {
  const isControlled = colorScheme !== undefined;
  const [uncontrolledScheme, setUncontrolledScheme] = useState<SuperagentColorScheme>(
    defaultColorScheme ?? 'light',
  );
  // Controlled → the prop is the source of truth (resolved during render, so the
  // subtree never paints a stale scheme); uncontrolled → local state.
  const scheme = isControlled ? colorScheme : uncontrolledScheme;
  // Sync the module-level scheme during render so themed styles resolve correctly
  // for the whole subtree rendered after this point.
  syncSuperagentColorScheme(scheme);

  const setScheme = useCallback(
    (next: SuperagentColorScheme) => {
      // In controlled mode the host owns the value — only notify; never fork local
      // state (which would let context drift from the prop).
      if (!isControlled) {
        setUncontrolledScheme(next);
      }
      onColorSchemeChange?.(next);
    },
    [isControlled, onColorSchemeChange],
  );
  const value = useMemo(() => ({ scheme, setScheme }), [scheme, setScheme]);

  return <SuperagentThemeContext.Provider value={value}>{children}</SuperagentThemeContext.Provider>;
}

interface SuperagentScreenProps {
  children: ReactNode;
  /** Extra surface styles (merged after the DS canvas background). */
  style?: StyleProp<ViewStyle>;
  /**
   * Pass `colorScheme` (controlled) or `defaultColorScheme` (uncontrolled) to have
   * this surface set up its own `SuperagentThemeProvider` (standalone/root screen).
   * Omit both when rendering inside an existing provider — the surface then
   * inherits the ambient scheme.
   */
  colorScheme?: SuperagentColorScheme;
  defaultColorScheme?: SuperagentColorScheme;
  onColorSchemeChange?: (scheme: SuperagentColorScheme) => void;
}

// Surface lives in its own component so its themed `shellStyles` read happens
// when React renders it — i.e. AFTER an enclosing provider has synced the active
// scheme. Reading the proxy inline in `SuperagentScreen` would resolve against
// the pre-sync scheme when `SuperagentScreen` also sets up the provider.
function ThemedSurface({ style, children }: { style?: StyleProp<ViewStyle>; children: ReactNode }) {
  // Plain View (not SafeAreaView): this surface is edge-to-edge by contract, so
  // safe-area insets are each screen's concern (e.g. SuperagentTopBar pads the
  // status bar itself). A SafeAreaView here would double-inset such screens.
  return <View style={[shellStyles.screen, style]}>{children}</View>;
}

export function SuperagentScreen({
  children,
  style,
  colorScheme,
  defaultColorScheme,
  onColorSchemeChange,
}: SuperagentScreenProps) {
  // Nested usage (no scheme props) inherits the ambient provider.
  if (colorScheme === undefined && defaultColorScheme === undefined) {
    return <ThemedSurface style={style}>{children}</ThemedSurface>;
  }
  return (
    <SuperagentThemeProvider
      colorScheme={colorScheme}
      defaultColorScheme={defaultColorScheme}
      onColorSchemeChange={onColorSchemeChange}
    >
      <ThemedSurface style={style}>{children}</ThemedSurface>
    </SuperagentThemeProvider>
  );
}
