import { createContext, useContext } from 'react';
import Head from 'next/head';

import type { CSSProperties, FC, ReactNode } from 'react';
import type { ItemContext } from '../../types';

import { isColorLight, toRgba } from '~/src/lib/utils/color';
import { toButtonStyleCss } from './utils';

interface PageThemeValue {
  backgroundColor: string;
  textColor: string;
  customFontColor?: string;
  fontFamily?: string;
  gradientOpacity: number;
  /**
   * `backgroundColor` pre-baked with `gradientOpacity` as alpha. Use for
   * plain overlay gradients (e.g. SingleColumnLayout's fade-to-bg).
   * For Scroller2's overflow gradient, pass `backgroundColor` + a scaled
   * `gradientAlpha` instead (see SingleColumnLayout/index.tsx:157).
   */
  gradientColor: string;
  buttonStyle: CSSProperties;
}

export const DEFAULT_GRADIENT_OPACITY = 100;

const DEFAULT_BACKGROUND_COLOR = '#000';

const DEFAULT_THEME: PageThemeValue = {
  backgroundColor: DEFAULT_BACKGROUND_COLOR,
  fontFamily: undefined,
  textColor: '#fff',
  gradientOpacity: DEFAULT_GRADIENT_OPACITY,
  gradientColor: toRgba(
    DEFAULT_BACKGROUND_COLOR,
    DEFAULT_GRADIENT_OPACITY / 100
  ),
  buttonStyle: toButtonStyleCss(),
};

const PageThemeContext = createContext<PageThemeValue>(DEFAULT_THEME);

export const PageThemeProvider: FC<{
  itemContext: ItemContext | undefined;
  children: ReactNode;
}> = ({ itemContext, children }) => {
  const themeAddon = itemContext?.addons.THEME;

  const value = {
    ...DEFAULT_THEME,
    ...themeAddon,

    gradientOpacity:
      themeAddon?.gradientOpacity ?? DEFAULT_THEME.gradientOpacity,

    buttonStyle: {
      ...DEFAULT_THEME.buttonStyle,
      ...toButtonStyleCss(itemContext?.addons.BUTTON_STYLE),
    },
  };

  const defaultColor = isColorLight(value.backgroundColor) ? '#000' : '#fff';

  return (
    <PageThemeContext.Provider
      value={{
        ...value,
        textColor: defaultColor,
        customFontColor: value.textColor,
        gradientColor: toRgba(
          value.backgroundColor,
          value.gradientOpacity / 100
        ),
      }}
    >
      {children}
      {value.fontFamily && (
        <Head>
          <link
            // These font weights match up with the weights used in <Text>. If some fonts look to heavy/light
            // at these weights we could configure these on the per-font basis.
            href={`/api/fonts/css?family=${value.fontFamily}:wght@400;500;700&display=swap`}
            rel="stylesheet"
          />
        </Head>
      )}
    </PageThemeContext.Provider>
  );
};

export const usePageTheme = () => useContext(PageThemeContext);
