import type { HTMLAttributes, ReactNode, ElementType } from 'react'
import type { SpaceToken } from './tokens.js'

/**
 * Responsive column count. Pass a number for static grids, or a map to
 * change column count at each breakpoint.
 *
 * @example
 *   columns={3}                              // 3 cols at every breakpoint
 *   columns={{ base: 1, md: 2, lg: 4 }}      // responsive
 */
export type GridResponsive =
  | number
  | { base?: number; sm?: number; md?: number; lg?: number; xl?: number; '2xl'?: number }

export interface GridProps extends HTMLAttributes<HTMLElement> {
  columns: GridResponsive
  /** Gap between cells. */
  space?: SpaceToken
  /** Row gap (defaults to `space`). */
  rowSpace?: SpaceToken
  /** Render as a different element. Defaults to `div`. */
  as?: ElementType
  /**
   * Use auto-fit instead of explicit column counts. When set, `minItemWidth`
   * controls the minimum tile width before the grid reflows. Use this for
   * card grids that should adapt to container width without specific
   * breakpoints.
   */
  autoFit?: boolean
  /** Min tile width when `autoFit` is true. Defaults to `16rem`. */
  minItemWidth?: string
  children?: ReactNode
}

const COL_CLASS: Record<number, string> = {
  1: 'grid-cols-1',
  2: 'grid-cols-2',
  3: 'grid-cols-3',
  4: 'grid-cols-4',
  5: 'grid-cols-5',
  6: 'grid-cols-6',
  7: 'grid-cols-7',
  8: 'grid-cols-8',
  9: 'grid-cols-9',
  10: 'grid-cols-10',
  11: 'grid-cols-11',
  12: 'grid-cols-12',
}

const BP_PREFIX = ['', 'sm:', 'md:', 'lg:', 'xl:', '2xl:'] as const
type BpKey = 'base' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'

function columnsToClasses(columns: GridResponsive): string {
  if (typeof columns === 'number') {
    return COL_CLASS[columns] ?? 'grid-cols-1'
  }
  const order: BpKey[] = ['base', 'sm', 'md', 'lg', 'xl', '2xl']
  return order
    .map((bp, i) => {
      const n = columns[bp]
      if (!n) return ''
      const base = COL_CLASS[n] ?? 'grid-cols-1'
      return BP_PREFIX[i] + base
    })
    .filter(Boolean)
    .join(' ')
}

/**
 * Responsive CSS grid primitive. Pass either an explicit `columns` count
 * (per-breakpoint or static) or set `autoFit` for a `repeat(auto-fit, …)`
 * tile grid. Both modes share the same `space` / `rowSpace` knobs so
 * usage is consistent across views.
 */
export function Grid({
  columns,
  space = '4',
  rowSpace,
  as: Component = 'div',
  autoFit,
  minItemWidth = '16rem',
  className = '',
  style,
  children,
  ...rest
}: GridProps) {
  if (autoFit) {
    return (
      <Component
        className={['grid', `gap-${space}`, rowSpace ? `gap-y-${rowSpace}` : '', className]
          .filter(Boolean)
          .join(' ')}
        style={{
          gridTemplateColumns: `repeat(auto-fit, minmax(${minItemWidth}, 1fr))`,
          ...style,
        }}
        {...rest}
      >
        {children}
      </Component>
    )
  }

  const classes = [
    'grid',
    columnsToClasses(columns),
    `gap-${space}`,
    rowSpace ? `gap-y-${rowSpace}` : '',
    className,
  ]
    .filter(Boolean)
    .join(' ')

  return (
    <Component className={classes} style={style} {...rest}>
      {children}
    </Component>
  )
}
