//
// Copyright 2022 DXOS.org
//

import { createKeyborg } from 'keyborg';
import React, { type PropsWithChildren, createContext, useEffect, useMemo } from 'react';

import { type Density, type Elevation, type ThemeFunction, type ThemeMode } from '@dxos/ui-types';

import { type SafeAreaPadding, useSafeArea } from '../../hooks';
import { hasIosKeyboard } from '../../util';
import { DensityProvider } from '../DensityProvider';
import { ElevationProvider } from '../ElevationProvider';
import { TranslationsProvider, type TranslationsProviderProps } from './TranslationsProvider';

export type ThemeContextValue = {
  tx: ThemeFunction<any>;
  themeMode: ThemeMode;
  hasIosKeyboard: boolean;
  safeAreaPadding?: SafeAreaPadding;
  noCache?: boolean;
  platform?: 'mobile' | 'desktop';
};

/**
 * @internal
 */
export const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);

export type ThemeProviderProps = Omit<TranslationsProviderProps, 'children'> &
  Partial<Omit<ThemeContextValue, 'safeAreaPadding'>> &
  PropsWithChildren<{
    rootDensity?: Density;
    rootElevation?: Elevation;
  }>;

export const ThemeProvider = ({
  children,
  fallback = null,
  resourceExtensions,
  appNs,
  tx = (_path, _styleProps, ..._options) => undefined,
  themeMode = 'dark',
  rootDensity = 'md',
  noCache,
  platform,
}: ThemeProviderProps) => {
  useEffect(() => {
    if (document.defaultView) {
      const kb = createKeyborg(document.defaultView);
      kb.subscribe(handleInputModalityChange);
      return () => kb.unsubscribe(handleInputModalityChange);
    }
  }, []);

  const safeAreaPadding = useSafeArea();
  // Destructure all props explicitly so useMemo deps are stable primitives, not a new `rest` object every render.
  const contextValue = useMemo(
    () => ({ tx, themeMode, hasIosKeyboard: hasIosKeyboard(), safeAreaPadding, noCache, platform }),
    [tx, themeMode, safeAreaPadding, noCache, platform],
  );

  return (
    <ThemeContext.Provider value={contextValue}>
      <TranslationsProvider
        {...{
          fallback,
          resourceExtensions,
          appNs,
        }}
      >
        <ElevationProvider elevation='base'>
          <DensityProvider density={rootDensity}>{children}</DensityProvider>
        </ElevationProvider>
      </TranslationsProvider>
    </ThemeContext.Provider>
  );
};

const handleInputModalityChange = (isUsingKeyboard: boolean) => {
  if (isUsingKeyboard) {
    document.body.setAttribute('data-w-keyboard', 'true');
  } else {
    document.body.removeAttribute('data-w-keyboard');
  }
};
