/* eslint-disable no-shadow */
// https://app.zeplin.io/styleguide/5d1436f1e97c2156f49c0725/colors
import { createTheme as _createTheme, responsiveFontSizes, type PaletteMode } from '@mui/material';
import webfontloader from 'webfontloader';
import {
  BLOCKLET_THEME_LIGHT,
  BLOCKLET_THEME_DARK,
  DEFAULT_FONTS,
  mergeThemeOptions as deepmerge,
  getDefaultThemePrefer,
  getBlockletThemeOptions,
  type ThemeOptions,
  type Theme,
} from '@blocklet/theme';
import { cleanedObj, deepmergeAll } from '../Util';

// 默认只加载最基本的 Roboto latin 字体
import '@fontsource/roboto/latin-400.css';
import '@fontsource/roboto/latin-500.css';
import '@fontsource/roboto/latin-700.css';
import '@fontsource/roboto/latin-ext-400.css';
import '@fontsource/roboto/latin-ext-500.css';
import '@fontsource/roboto/latin-ext-700.css';

/** 是否是 MUI Theme 对象 */
export function isTheme(obj: any): obj is Theme {
  return obj && typeof obj === 'object' && obj.palette && typeof obj.palette.getContrastText === 'function';
}

/** 是否是 UX Theme 对象 */
export function isUxTheme(obj: any): obj is Theme {
  return isTheme(obj) && obj.__isUxTheme__ === true;
}

// 收集字体配置
export function collectFontFamilies(obj?: { fontFamily?: string }, fontSet: Set<string> = new Set()): Set<string> {
  if (!obj || typeof obj !== 'object') return fontSet;

  if (typeof obj.fontFamily === 'string') {
    obj.fontFamily
      .replace(/"/g, '')
      .split(',')
      .map((font: string) => font.trim())
      .filter(Boolean)
      .forEach((font: string) => fontSet.add(font));
  }

  Object.values(obj).forEach((value) => {
    if (typeof value === 'object') {
      collectFontFamilies(value, fontSet);
    }
  });

  return fontSet;
}

// 动态加载字体
const prevFonts = new Set<string>(DEFAULT_FONTS.concat('inherit')); // inherit 属于 MUI 特殊值，无需动态加载
export function loadFonts(fonts: string[]) {
  // 过滤出未加载的字体
  const unloadedFonts = fonts.filter((font) => !prevFonts.has(font));

  // 如果所有字体都已加载，直接返回
  if (unloadedFonts.length === 0) {
    return Promise.resolve(true);
  }

  // record
  unloadedFonts.forEach((font) => prevFonts.add(font));

  // support font-display: swap
  const lastFontIndex = unloadedFonts.length - 1;
  unloadedFonts[lastFontIndex] = `${unloadedFonts[lastFontIndex]}&display=swap`;

  return new Promise<boolean>((resolve) => {
    webfontloader.load({
      google: {
        families: unloadedFonts,
      },
      active: () => resolve(true),
      inactive: () => resolve(true),
      fontinactive: (familyName, fvd) => {
        prevFonts.delete(familyName);
        console.warn(`font ${familyName} ${fvd} download failed`);
      },
    });
  });
}

// 创建默认主题配置
export function createDefaultThemeOptions(mode: PaletteMode = 'light') {
  if (mode === 'dark') {
    return BLOCKLET_THEME_DARK;
  }

  return BLOCKLET_THEME_LIGHT;
}

export interface UxThemeOptions extends ThemeOptions {
  disableBlockletTheme?: boolean;
}

export function lazyCreateDefaultTheme(mode: PaletteMode) {
  let theme: Theme | null = null;

  return () => {
    if (theme) return theme;

    const options = deepmerge(createDefaultThemeOptions(mode), getBlockletThemeOptions(mode));

    theme = _createTheme(options);
    return theme;
  };
}

// 主要处理 overrides
const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }: UxThemeOptions) => {
  const result: UxThemeOptions = {
    palette,
    components: {
      ...overrides,
      ...components,
    },
    ...rest,
  };

  return result;
};

const defaultUxThemeOptions: UxThemeOptions = {
  themeName: 'ArcBlock',
  pageWidth: 'md',
  disableBlockletTheme: false,
  // @deprecated use theme.palette
  colors: {
    white: '#FFFFFF',
    dark: '#4A707C',
    gray: '#222222',
    minor: '#9B9B9B',
    darkText: '#DCDCDC',
    background: '#F7F8F8',
    yellow: '#FFCF71',
    green: '#44cdc6',
    red: '#D0021B',
    blue: '#4E6AF6',
    primary: '#222222',
    black: '#222222',
    secondary: '#44cdc6',
    mint: '#44cdc6',
    textSecondary: '#4A4A4A',
    active: '#5b9025',
    danger: '#D0021B',
    lightGrey: '#BCBCBC',
  },
};

// https://material-ui.com/customization/default-theme/
export const create = (...args: Array<UxThemeOptions | ((baseTheme: Theme) => UxThemeOptions)>) => {
  const defaultPrefer = getDefaultThemePrefer();
  const createBaseTheme = lazyCreateDefaultTheme(defaultPrefer);
  const userThemeOptions = args.reduce<UxThemeOptions>(
    (acc, curr) =>
      deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(createBaseTheme()) : curr)),
    normalizeUserThemeOptions(defaultUxThemeOptions)
  );
  const prefer = userThemeOptions.mode || userThemeOptions.palette?.mode || defaultPrefer;
  const blockletThemeOptions = getBlockletThemeOptions(prefer);
  const defaultThemeOptions = createDefaultThemeOptions(prefer);
  const { disableBlockletTheme } = userThemeOptions;

  // 合并配置
  const mergedThemeOptions = deepmergeAll(
    [
      defaultThemeOptions,
      !disableBlockletTheme && cleanedObj(blockletThemeOptions),
      cleanedObj(userThemeOptions),
      // 确保 mode 跟 prefer 一致
      {
        mode: prefer,
        palette: { mode: prefer },
      },
    ].filter(Boolean) as ThemeOptions[]
  );

  // 创建主题
  const theme = _createTheme(mergedThemeOptions);
  theme.__isUxTheme__ = true;

  // 异步加载字体
  const fonts = collectFontFamilies(theme.typography);
  loadFonts(Array.from(fonts));

  /**
   * 支持响应式字体，theme.typography.$variant 中会添加 @media 分支，比如
   * {
   *  "h1": {
   *    "fontSize": "3rem",
   *    "@media (min-width:600px)": {
   *      "fontSize": "3.3125rem"
   *    }
   *  }
   * }
   */
  const enhanced = responsiveFontSizes(theme, {
    breakpoints: ['xs', 'sm', 'md', 'lg'],
    disableAlign: false,
    factor: 3,
    variants: [
      'h1',
      'h2',
      'h3',
      'h4',
      'h5',
      'h6',
      'subtitle1',
      'subtitle2',
      'body1',
      'body2',
      'caption',
      'button',
      'overline',
    ],
  });

  return enhanced;
};

export const createTheme = create;
export { deepmerge, deepmergeAll };
