import type { DeepPartial } from '@furystack/utils'
import type { Theme } from './theme-provider-service.js'
export const cssVariableTheme = {
  name: 'css-variable-theme',
  text: {
    primary: 'var(--shades-theme-text-primary)',
    secondary: 'var(--shades-theme-text-secondary)',
    disabled: 'var(--shades-theme-text-disabled)',
  },
  button: {
    active: 'var(--shades-theme-button-active)',
    hover: 'var(--shades-theme-button-hover)',
    selected: 'var(--shades-theme-button-selected)',
    disabled: 'var(--shades-theme-button-disabled)',
    disabledBackground: 'var(--shades-theme-button-disabled-background)',
  },
  background: {
    default: 'var(--shades-theme-background-default)',
    paper: 'var(--shades-theme-background-paper)',
    paperImage: 'var(--shades-theme-background-paper-image)',
  },
  palette: {
    primary: {
      light: 'var(--shades-theme-palette-primary-light)',
      lightContrast: 'var(--shades-theme-palette-primary-light-contrast)',
      main: 'var(--shades-theme-palette-primary-main)',
      mainContrast: 'var(--shades-theme-palette-primary-main-contrast)',
      dark: 'var(--shades-theme-palette-primary-dark)',
      darkContrast: 'var(--shades-theme-palette-primary-dark-contrast)',
    },
    secondary: {
      light: 'var(--shades-theme-palette-secondary-light)',
      lightContrast: 'var(--shades-theme-palette-secondary-light-contrast)',
      main: 'var(--shades-theme-palette-secondary-main)',
      mainContrast: 'var(--shades-theme-palette-secondary-main-contrast)',
      dark: 'var(--shades-theme-palette-secondary-dark)',
      darkContrast: 'var(--shades-theme-palette-secondary-dark-contrast)',
    },
    error: {
      light: 'var(--shades-theme-palette-error-light)',
      lightContrast: 'var(--shades-theme-palette-error-light-contrast)',
      main: 'var(--shades-theme-palette-error-main)',
      mainContrast: 'var(--shades-theme-palette-error-main-contrast)',
      dark: 'var(--shades-theme-palette-error-dark)',
      darkContrast: 'var(--shades-theme-palette-error-dark-contrast)',
    },
    warning: {
      light: 'var(--shades-theme-palette-warning-light)',
      lightContrast: 'var(--shades-theme-palette-warning-light-contrast)',
      main: 'var(--shades-theme-palette-warning-main)',
      mainContrast: 'var(--shades-theme-palette-warning-main-contrast)',
      dark: 'var(--shades-theme-palette-warning-dark)',
      darkContrast: 'var(--shades-theme-palette-warning-dark-contrast)',
    },
    info: {
      light: 'var(--shades-theme-palette-info-light)',
      lightContrast: 'var(--shades-theme-palette-info-light-contrast)',
      main: 'var(--shades-theme-palette-info-main)',
      mainContrast: 'var(--shades-theme-palette-info-main-contrast)',
      dark: 'var(--shades-theme-palette-info-dark)',
      darkContrast: 'var(--shades-theme-palette-info-dark-contrast)',
    },
    success: {
      light: 'var(--shades-theme-palette-success-light)',
      lightContrast: 'var(--shades-theme-palette-success-light-contrast)',
      main: 'var(--shades-theme-palette-success-main)',
      mainContrast: 'var(--shades-theme-palette-success-main-contrast)',
      dark: 'var(--shades-theme-palette-success-dark)',
      darkContrast: 'var(--shades-theme-palette-success-dark-contrast)',
    },
  },
  divider: 'var(--shades-theme-divider)',
  action: {
    hoverBackground: 'var(--shades-theme-action-hover-background)',
    selectedBackground: 'var(--shades-theme-action-selected-background)',
    activeBackground: 'var(--shades-theme-action-active-background)',
    focusRing: 'var(--shades-theme-action-focus-ring)',
    focusOutline: 'var(--shades-theme-action-focus-outline)',
    disabledOpacity: 'var(--shades-theme-action-disabled-opacity)',
    backdrop: 'var(--shades-theme-action-backdrop)',
    subtleBorder: 'var(--shades-theme-action-subtle-border)',
  },
  shape: {
    borderRadius: {
      xs: 'var(--shades-theme-shape-border-radius-xs)',
      sm: 'var(--shades-theme-shape-border-radius-sm)',
      md: 'var(--shades-theme-shape-border-radius-md)',
      lg: 'var(--shades-theme-shape-border-radius-lg)',
      full: 'var(--shades-theme-shape-border-radius-full)',
    },
    borderWidth: 'var(--shades-theme-shape-border-width)',
  },
  shadows: {
    none: 'var(--shades-theme-shadows-none)',
    sm: 'var(--shades-theme-shadows-sm)',
    md: 'var(--shades-theme-shadows-md)',
    lg: 'var(--shades-theme-shadows-lg)',
    xl: 'var(--shades-theme-shadows-xl)',
  },
  typography: {
    fontFamily: 'var(--shades-theme-typography-font-family)',
    fontSize: {
      xs: 'var(--shades-theme-typography-font-size-xs)',
      sm: 'var(--shades-theme-typography-font-size-sm)',
      md: 'var(--shades-theme-typography-font-size-md)',
      lg: 'var(--shades-theme-typography-font-size-lg)',
      xl: 'var(--shades-theme-typography-font-size-xl)',
      xxl: 'var(--shades-theme-typography-font-size-xxl)',
      xxxl: 'var(--shades-theme-typography-font-size-xxxl)',
      xxxxl: 'var(--shades-theme-typography-font-size-xxxxl)',
    },
    fontWeight: {
      normal: 'var(--shades-theme-typography-font-weight-normal)',
      medium: 'var(--shades-theme-typography-font-weight-medium)',
      semibold: 'var(--shades-theme-typography-font-weight-semibold)',
      bold: 'var(--shades-theme-typography-font-weight-bold)',
    },
    lineHeight: {
      tight: 'var(--shades-theme-typography-line-height-tight)',
      normal: 'var(--shades-theme-typography-line-height-normal)',
      relaxed: 'var(--shades-theme-typography-line-height-relaxed)',
    },
    letterSpacing: {
      tight: 'var(--shades-theme-typography-letter-spacing-tight)',
      dense: 'var(--shades-theme-typography-letter-spacing-dense)',
      normal: 'var(--shades-theme-typography-letter-spacing-normal)',
      wide: 'var(--shades-theme-typography-letter-spacing-wide)',
      wider: 'var(--shades-theme-typography-letter-spacing-wider)',
      widest: 'var(--shades-theme-typography-letter-spacing-widest)',
    },
    textShadow: 'var(--shades-theme-typography-text-shadow)',
  },
  transitions: {
    duration: {
      fast: 'var(--shades-theme-transitions-duration-fast)',
      normal: 'var(--shades-theme-transitions-duration-normal)',
      slow: 'var(--shades-theme-transitions-duration-slow)',
    },
    easing: {
      default: 'var(--shades-theme-transitions-easing-default)',
      easeOut: 'var(--shades-theme-transitions-easing-ease-out)',
      easeInOut: 'var(--shades-theme-transitions-easing-ease-in-out)',
    },
  },
  spacing: {
    xs: 'var(--shades-theme-spacing-xs)',
    sm: 'var(--shades-theme-spacing-sm)',
    md: 'var(--shades-theme-spacing-md)',
    lg: 'var(--shades-theme-spacing-lg)',
    xl: 'var(--shades-theme-spacing-xl)',
  },
  zIndex: {
    drawer: 'var(--shades-theme-z-index-drawer)',
    appBar: 'var(--shades-theme-z-index-app-bar)',
    modal: 'var(--shades-theme-z-index-modal)',
    tooltip: 'var(--shades-theme-z-index-tooltip)',
    dropdown: 'var(--shades-theme-z-index-dropdown)',
  },
  effects: {
    blurSm: 'var(--shades-theme-effects-blur-sm)',
    blurMd: 'var(--shades-theme-effects-blur-md)',
    blurLg: 'var(--shades-theme-effects-blur-lg)',
    blurXl: 'var(--shades-theme-effects-blur-xl)',
  },
} satisfies Theme

/**
 * Builds a CSS transition string from property-duration-easing triplets.
 * @param specs - Array of [property, duration, easing] tuples
 * @returns A CSS transition string
 * @example
 * buildTransition(
 *   ['background', cssVariableTheme.transitions.duration.normal, cssVariableTheme.transitions.easing.default],
 *   ['opacity', cssVariableTheme.transitions.duration.fast, 'ease-out'],
 * )
 */
export const buildTransition = (...specs: Array<[property: string, duration: string, easing: string]>): string =>
  specs.map(([prop, dur, ease]) => `${prop} ${dur} ${ease}`).join(', ')

const FOCUS_STYLES_ID = 'shades-focus-visible-styles'

/**
 * Injects global `:focus-visible` styles using the theme's `focusOutline` CSS variable.
 * Ensures keyboard/spatial navigation focus is visible while mouse clicks produce no outline.
 * Safe to call multiple times — the style element is only created once.
 */
export const injectFocusVisibleStyles = (): void => {
  if (document.getElementById(FOCUS_STYLES_ID)) return

  const style = document.createElement('style')
  style.id = FOCUS_STYLES_ID
  style.textContent = `
:focus-visible {
  outline: ${cssVariableTheme.action.focusOutline};
  outline-offset: 2px;
}
:focus:not(:focus-visible) {
  outline: none;
}
`
  document.head.appendChild(style)
}

const extractVarName = (key: string): string => key.replace(/^var\(/, '').replace(/[,)].*/, '')

export const setCssVariable = (key: string, value: string, root: HTMLElement) => {
  root.style.setProperty(extractVarName(key), value)
}

export const removeCssVariable = (key: string, root: HTMLElement) => {
  root.style.removeProperty(extractVarName(key))
}

export const getCssVariable = (key: string, root: HTMLElement = document.querySelector(':root') as HTMLElement) => {
  return getComputedStyle(root).getPropertyValue(extractVarName(key))
}

const removeValue = <T extends object>(target: T, root: HTMLElement) => {
  const keys = Object.keys(target) as Array<keyof T>
  keys.forEach((key) => {
    if (typeof target[key] === 'object') {
      removeValue(target[key] as object, root)
    } else {
      removeCssVariable(target[key] as string, root)
    }
  })
}

const assignValue = <T extends object>(
  target: T,
  source: DeepPartial<T>,
  root: HTMLElement,
  assignFn = setCssVariable,
) => {
  const keys = Object.keys(target) as Array<keyof T>
  keys.forEach((key) => {
    if (typeof target[key] === 'object') {
      if (source[key] === undefined) {
        removeValue(target[key] as object, root)
      } else {
        assignValue(target[key] as object, source[key], root, assignFn)
      }
    } else if (source[key] === undefined) {
      removeCssVariable(target[key] as string, root)
    } else {
      assignFn(target[key] as string, source[key] as string, root)
    }
  })
}
export const useThemeCssVariables = (theme: DeepPartial<Theme>, root?: HTMLElement) => {
  root ??= document.querySelector(':root') as HTMLElement
  assignValue(cssVariableTheme, theme, root)

  if (window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches) {
    setCssVariable(cssVariableTheme.transitions.duration.fast, '0s', root)
    setCssVariable(cssVariableTheme.transitions.duration.normal, '0s', root)
    setCssVariable(cssVariableTheme.transitions.duration.slow, '0s', root)
  }
}
