/// <reference path="../../lynx.d.ts" />
/**
 * Rating Component - Lynx 版 MUI Rating
 * 100% 一比一复刻 MUI Rating
 * 
 * 星级评分组件，支持小数评分和自定义图标
 * 
 * 对应 MUI: packages/mui-material/src/Rating/Rating.js
 */
import './Rating.css'
import ratingClasses, { getRatingUtilityClass } from './ratingClasses'
export { ratingClasses, getRatingUtilityClass }

// =============================================
// 类型定义
// =============================================

export type RatingSize = 'small' | 'medium' | 'large'

export interface RatingProps {
  /** 自定义类名 */
  className?: string
  /** 样式类覆盖 */
  classes?: Partial<typeof ratingClasses>
  /** 默认评分 */
  defaultValue?: number
  /** 是否禁用 */
  disabled?: boolean
  /** 空图标 */
  emptyIcon?: any
  /** 空值标签 */
  emptyLabelText?: string
  /** 最大评分 */
  max?: number
  /** 当前评分 */
  value?: number
  /** 精度 */
  precision?: number
  /** 是否只读 */
  readOnly?: boolean
  /** 尺寸 */
  size?: RatingSize
  /** 获取标签文本 */
  getLabelText?: (value: number) => string
  /** 高精度图标 */
  icon?: any
  /** 活动图标 */
  activeIcon?: any
  /** 内联样式 */
  style?: Record<string, any>
  /** sx 属性 */
  sx?: Record<string, any>
  /** 点击事件 */
  bindtap?: (event?: any) => void
  onChange?: (event: any, value: number | null) => void
  onChangeActive?: (event: any, value: number) => void
  onHover?: (event: any, value: number) => void
}

// =============================================
// 辅助函数
// =============================================

function capitalize(str: string): string {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

function composeClasses(
  slots: Record<string, (string | boolean | null | undefined)[]>,
  getUtilityClass: (slot: string) => string,
  classes?: Record<string, string>
): Record<string, string> {
  const output: Record<string, string> = {}
  
  Object.keys(slots).forEach((slot) => {
    output[slot] = slots[slot]
      .filter(Boolean)
      .map((key) => {
        if (classes && classes[key as string]) {
          return `${getUtilityClass(key as string)} ${classes[key as string]}`
        }
        return getUtilityClass(key as string)
      })
      .join(' ')
  })
  
  return output
}

function clamp(value: number, min: number, max: number): number {
  return Math.min(Math.max(value, min), max)
}

function getDecimalPrecision(num: number): number {
  const decimalPart = num.toString().split('.')[1]
  return decimalPart ? decimalPart.length : 0
}

function roundValueToPrecision(value: number, precision: number): number {
  if (value == null) {
    return value
  }

  const nearest = Math.round(value / precision) * precision
  return Number(nearest.toFixed(getDecimalPrecision(precision)))
}

// =============================================
// useUtilityClasses
// =============================================

interface OwnerState extends RatingProps {
  emptyValueFocused?: boolean
  focusVisible?: boolean
}

function useUtilityClasses(ownerState: OwnerState) {
  const { 
    classes, 
    size = 'medium', 
    readOnly, 
    disabled, 
    emptyValueFocused, 
    focusVisible 
  } = ownerState

  const slots = {
    root: [
      'root',
      `size${capitalize(size)}`,
      disabled && 'disabled',
      focusVisible && 'focusVisible',
      readOnly && 'readOnly',
    ],
    label: ['label', 'pristine'],
    labelEmptyValue: [emptyValueFocused && 'labelEmptyValueActive'],
    icon: ['icon'],
    iconEmpty: ['iconEmpty'],
    iconFilled: ['iconFilled'],
    iconHover: ['iconHover'],
    iconFocus: ['iconFocus'],
    iconActive: ['iconActive'],
    decimal: ['decimal'],
    visuallyHidden: ['visuallyHidden'],
  }

  return composeClasses(slots, getRatingUtilityClass, classes)
}

// =============================================
// Rating 组件
// =============================================

export function Rating(props: RatingProps) {
  const {
    className,
    classes: classesProp,
    defaultValue = 0,
    disabled = false,
    emptyIcon,
    emptyLabelText = 'Empty',
    max = 5,
    value: valueProp,
    precision = 1,
    readOnly = false,
    size = 'medium',
    getLabelText = (value: number) => `${value} Star${value !== 1 ? 's' : ''}`,
    icon,
    activeIcon,
    style,
    sx,
    bindtap,
    onChange,
    onChangeActive,
    onHover,
    ...other
  } = props

  // 在 Lynx 环境下，组件必须是受控的
  // 如果没有提供 value 属性，使用默认值
  const value = valueProp !== undefined ? valueProp : defaultValue

  const ownerState: OwnerState = {
    ...props,
    value,
    disabled,
    readOnly,
    size,
  }

  const classes = useUtilityClasses(ownerState)

  // 处理点击事件
  const handleTap = (event?: any, newValue?: number) => {
    if (disabled || readOnly) return

    if (newValue !== undefined) {
      const clampedValue = clamp(newValue, 0, max)
      const roundedValue = roundValueToPrecision(clampedValue, precision)
      
      if (onChange) {
        onChange(event, roundedValue === 0 ? null : roundedValue)
      }
    }

    if (bindtap) bindtap(event)
  }

  // 处理悬停事件
  const handleHover = (event?: any, newValue?: number) => {
    if (disabled || readOnly) return

    if (onHover && newValue !== undefined) {
      onHover(event, newValue)
    }
  }

  // 渲染星星图标
  const renderStars = () => {
    const stars = []
    const clampedValue = clamp(value, 0, max)
    
    for (let index = 0; index < max; index += 1) {
      const itemValue = index + 1
      
      // 判断是否填充
      const isFilled = clampedValue >= itemValue
      // 判断是否部分填充（小数）
      const isFraction = clampedValue > index && clampedValue < itemValue
      
      stars.push(
        <view
          key={index}
          className={[
            ratingClasses.icon,
            isFilled ? ratingClasses.iconFilled : ratingClasses.iconEmpty,
            isFraction && ratingClasses.decimal,
          ].filter(Boolean).join(' ')}
          bindtap={(e: any) => handleTap(e, itemValue)}
          style={{ cursor: disabled || readOnly ? 'default' : 'pointer' }}
        >
          {/* 使用 CSS 实现星星图标 */}
          <view className="MuiRating-starIcon" />
        </view>
      )
    }

    return stars
  }

  // 构建类名
  const rootClasses = [
    classes.root,
    ratingClasses.root,
    className,
    ratingClasses[`size${capitalize(size)}` as keyof typeof ratingClasses],
    disabled && ratingClasses.disabled,
    readOnly && ratingClasses.readOnly,
  ].filter(Boolean).join(' ')

  return (
    <view
      className={rootClasses}
      style={sx ? { ...sx, ...style } : style}
      role="radiogroup"
      aria-label={getLabelText(value)}
      {...other}
    >
      <view className={ratingClasses.visuallyHidden}>
        <text>{getLabelText(value)}</text>
      </view>
      {renderStars()}
    </view>
  )
}

export default Rating
