import type { PartialElement } from '@furystack/shades'
import { Shade, createComponent } from '@furystack/shades'
import { buildTransition, cssVariableTheme } from '../../services/css-variable-theme.js'
import type { Palette } from '../../services/theme-provider-service.js'
import { ThemeProviderService } from '../../services/theme-provider-service.js'
import type { ComponentSize } from '../component-size.js'
import { FormContextToken } from '../form.js'

export type SwitchProps = {
  /**
   * Whether the switch is checked (on)
   */
  checked?: boolean
  /**
   * Whether the switch is disabled
   */
  disabled?: boolean
  /**
   * The palette color for the switch
   */
  color?: keyof Palette
  /**
   * Callback when the checked state changes
   */
  onchange?: (event: Event) => void
  /**
   * Label text or element displayed next to the switch
   */
  labelTitle?: JSX.Element | string
  /**
   * The name attribute for the underlying input element
   */
  name?: string
  /**
   * The value attribute for the underlying input element
   */
  value?: string
  /**
   * Whether the switch is required
   */
  required?: boolean
  /**
   * The size of the switch
   */
  size?: ComponentSize
  /**
   * Optional props for the label element
   */
  labelProps?: PartialElement<HTMLLabelElement>
}

export const Switch = Shade<SwitchProps>({
  customElementName: 'shade-switch',
  css: {
    display: 'inline-flex',
    fontFamily: cssVariableTheme.typography.fontFamily,
    alignItems: 'center',

    '& label': {
      display: 'inline-flex',
      alignItems: 'center',
      gap: cssVariableTheme.spacing.sm,
      cursor: 'pointer',
      fontSize: cssVariableTheme.typography.fontSize.sm,
      color: cssVariableTheme.text.primary,
      userSelect: 'none',
      webkitUserSelect: 'none',
    },

    '& .switch-control': {
      position: 'relative',
      display: 'inline-flex',
      alignItems: 'center',
      flexShrink: '0',
    },

    // Medium size (default)
    '& .switch-track': {
      width: '40px',
      height: '22px',
      borderRadius: '11px',
      backgroundColor: cssVariableTheme.text.secondary,
      transition: buildTransition([
        'background-color',
        cssVariableTheme.transitions.duration.fast,
        cssVariableTheme.transitions.easing.default,
      ]),
      position: 'relative',
      opacity: '0.5',
    },

    '& .switch-thumb': {
      position: 'absolute',
      top: '2px',
      left: '2px',
      width: '18px',
      height: '18px',
      borderRadius: '50%',
      background: cssVariableTheme.background.paper,
      transition: buildTransition(
        ['transform', cssVariableTheme.transitions.duration.fast, cssVariableTheme.transitions.easing.default],
        ['box-shadow', cssVariableTheme.transitions.duration.fast, cssVariableTheme.transitions.easing.default],
      ),
      boxShadow: cssVariableTheme.shadows.sm,
      pointerEvents: 'none',
    },

    // Small size
    '&[data-size="small"] .switch-track': {
      width: '32px',
      height: '18px',
      borderRadius: '9px',
    },

    '&[data-size="small"] .switch-thumb': {
      width: '14px',
      height: '14px',
    },

    // Large size
    '&[data-size="large"] .switch-track': {
      width: '48px',
      height: '26px',
      borderRadius: '13px',
    },

    '&[data-size="large"] .switch-thumb': {
      width: '22px',
      height: '22px',
    },

    // Hidden input
    '& input[type="checkbox"]': {
      position: 'absolute',
      width: '1px',
      height: '1px',
      margin: '-1px',
      padding: '0',
      overflow: 'hidden',
      clip: 'rect(0, 0, 0, 0)',
      whiteSpace: 'nowrap',
      border: '0',
    },

    // Checked state
    '& input[type="checkbox"]:checked + .switch-track': {
      backgroundColor: 'var(--switch-color)',
      opacity: '1',
    },

    '& input[type="checkbox"]:checked + .switch-track .switch-thumb': {
      transform: 'translateX(18px)',
    },

    '&[data-size="small"] input[type="checkbox"]:checked + .switch-track .switch-thumb': {
      transform: 'translateX(14px)',
    },

    '&[data-size="large"] input[type="checkbox"]:checked + .switch-track .switch-thumb': {
      transform: 'translateX(22px)',
    },

    // Hover state
    '& .switch-control:hover .switch-track': {
      opacity: '0.7',
    },

    '& .switch-control:hover input[type="checkbox"]:checked + .switch-track': {
      opacity: '0.85',
    },

    // Focus state
    '& input[type="checkbox"]:focus-visible + .switch-track': {
      outline: 'none',
      boxShadow: cssVariableTheme.action.focusRing,
    },

    // Disabled state
    '&[data-disabled] label': {
      color: cssVariableTheme.text.disabled,
      cursor: 'not-allowed',
    },

    '&[data-disabled] .switch-control': {
      opacity: cssVariableTheme.action.disabledOpacity,
      pointerEvents: 'none',
    },
  },
  render: ({ props, injector, useDisposable, useHostProps, useRef }) => {
    const inputRef = useRef<HTMLInputElement>('formInput')

    useDisposable('form-registration', () => {
      const formService = injector.get(FormContextToken)
      if (formService) {
        queueMicrotask(() => {
          if (inputRef.current) formService.inputs.add(inputRef.current)
        })
      }
      return {
        [Symbol.dispose]: () => {
          if (inputRef.current && formService) formService.inputs.delete(inputRef.current)
        },
      }
    })

    const themeProvider = injector.get(ThemeProviderService)

    const color = themeProvider.theme.palette[props.color || 'primary'].main
    useHostProps({
      'data-disabled': props.disabled ? '' : undefined,
      'data-size': props.size && props.size !== 'medium' ? props.size : undefined,
      style: { '--switch-color': color },
    })

    return (
      <label {...props.labelProps}>
        <span className="switch-control">
          <input
            ref={inputRef}
            type="checkbox"
            role="switch"
            checked={props.checked}
            disabled={props.disabled}
            name={props.name}
            required={props.required}
            {...(props.value !== undefined ? { value: props.value } : {})}
          />
          <span className="switch-track">
            <span className="switch-thumb" />
          </span>
        </span>
        {props.labelTitle ? <span className="switch-label">{props.labelTitle}</span> : null}
      </label>
    )
  },
})
