import React, { ReactNode, ElementType } from 'react';
import { Box, BoxProps, ResponsiveValue } from './Box';

/**
 * WARNING: DO NOT VIOLATE THE PURPOSE OF THIS PRIMITIVE.
 * 
 * Stack is for flexbox-based layouts (stacking elements).
 * 
 * - DO NOT add positioning props (absolute, top, zIndex).
 * - DO NOT add grid props.
 * - DO NOT add background/border props unless it's a specific styled stack.
 * 
 * If you need a more specific layout, create a new component in apps/website/components.
 */

type Spacing = 0 | 0.5 | 1 | 1.5 | 2 | 2.5 | 3 | 3.5 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | 64 | 72 | 80 | 96;

interface ResponsiveGap {
  base?: number;
  sm?: number;
  md?: number;
  lg?: number;
  xl?: number;
}

interface ResponsiveSpacing {
  base?: Spacing;
  sm?: Spacing;
  md?: Spacing;
  lg?: Spacing;
  xl?: Spacing;
  '2xl'?: Spacing;
}

export interface StackProps<T extends ElementType> {
  as?: T;
  children: ReactNode;
  className?: string;
  direction?: 'row' | 'col' | { base?: 'row' | 'col'; md?: 'row' | 'col'; lg?: 'row' | 'col' };
  gap?: number | ResponsiveGap;
  align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline' | ResponsiveValue<'start' | 'center' | 'end' | 'stretch' | 'baseline'>;
  justify?: 'start' | 'center' | 'end' | 'between' | 'around' | ResponsiveValue<'start' | 'center' | 'end' | 'between' | 'around'>;
  wrap?: boolean;
  // Spacing (allowed for layout)
  m?: Spacing | ResponsiveSpacing;
  mt?: Spacing | ResponsiveSpacing;
  mb?: Spacing | ResponsiveSpacing;
  ml?: Spacing | ResponsiveSpacing;
  mr?: Spacing | ResponsiveSpacing;
  p?: Spacing | ResponsiveSpacing;
  pt?: Spacing | ResponsiveSpacing;
  pb?: Spacing | ResponsiveSpacing;
  pl?: Spacing | ResponsiveSpacing;
  pr?: Spacing | ResponsiveSpacing;
  px?: Spacing | ResponsiveSpacing;
  py?: Spacing | ResponsiveSpacing;
  // Sizing (allowed for layout)
  w?: string | ResponsiveValue<string>;
  h?: string | ResponsiveValue<string>;
  minWidth?: string | ResponsiveValue<string>;
  maxWidth?: string | ResponsiveValue<string>;
  minHeight?: string | ResponsiveValue<string>;
  maxHeight?: string | ResponsiveValue<string>;
  // Basic styling (sometimes needed for containers)
  rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';
  // Flex item props
  flex?: number | string;
  flexGrow?: number;
  flexShrink?: number;
  alignSelf?: 'auto' | 'start' | 'end' | 'center' | 'stretch' | 'baseline';
  style?: React.CSSProperties;
}

export function Stack<T extends ElementType = 'div'>({ 
  children, 
  className = '', 
  direction = 'col',
  gap = 4,
  align,
  justify,
  wrap = false,
  m, mt, mb, ml, mr,
  p, pt, pb, pl, pr, px, py,
  w, h, minWidth, maxWidth, minHeight, maxHeight,
  rounded,
  flex,
  flexGrow,
  flexShrink,
  alignSelf,
  as,
  ...props
}: StackProps<T>) {
  const gapClasses: Record<number, string> = {
    0: 'gap-0',
    1: 'gap-1',
    2: 'gap-2',
    3: 'gap-3',
    4: 'gap-4',
    5: 'gap-5',
    6: 'gap-6',
    8: 'gap-8',
    10: 'gap-10',
    12: 'gap-12',
    16: 'gap-16'
  };

  const getGapClasses = (value: number | ResponsiveGap | undefined) => {
    if (value === undefined) return '';
    if (typeof value === 'object') {
      const classes = [];
      if (value.base !== undefined) classes.push(gapClasses[value.base]);
      if (value.sm !== undefined) classes.push(`sm:${gapClasses[value.sm]}`);
      if (value.md !== undefined) classes.push(`md:${gapClasses[value.md]}`);
      if (value.lg !== undefined) classes.push(`lg:${gapClasses[value.lg]}`);
      if (value.xl !== undefined) classes.push(`xl:${gapClasses[value.xl]}`);
      return classes.join(' ');
    }
    return gapClasses[value];
  };

  const spacingMap: Record<number, string> = {
    0: '0', 0.5: '0.5', 1: '1', 1.5: '1.5', 2: '2', 2.5: '2.5', 3: '3', 3.5: '3.5', 4: '4',
    5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', 11: '11', 12: '12', 14: '14',
    16: '16', 20: '20', 24: '24', 28: '28', 32: '32', 36: '36', 40: '40', 44: '44',
    48: '48', 52: '52', 56: '56', 60: '60', 64: '64', 72: '72', 80: '80', 96: '96'
  };

  const roundedClasses = {
    none: 'rounded-none',
    sm: 'rounded-sm',
    md: 'rounded-md',
    lg: 'rounded-lg',
    xl: 'rounded-xl',
    '2xl': 'rounded-2xl',
    full: 'rounded-full'
  };

  const getSpacingClass = (prefix: string, value: Spacing | ResponsiveSpacing | undefined) => {
    if (value === undefined) return '';
    if (typeof value === 'object') {
      const classes = [];
      if (value.base !== undefined) classes.push(`${prefix}-${spacingMap[value.base]}`);
      if (value.sm !== undefined) classes.push(`sm:${prefix}-${spacingMap[value.sm]}`);
      if (value.md !== undefined) classes.push(`md:${prefix}-${spacingMap[value.md]}`);
      if (value.lg !== undefined) classes.push(`lg:${prefix}-${spacingMap[value.lg]}`);
      if (value.xl !== undefined) classes.push(`xl:${prefix}-${spacingMap[value.xl]}`);
      if (value['2xl'] !== undefined) classes.push(`2xl:${prefix}-${spacingMap[value['2xl']]}`);
      return classes.join(' ');
    }
    return `${prefix}-${spacingMap[value]}`;
  };

  const classes = [
    'flex',
    typeof direction === 'string' 
      ? (direction === 'col' ? 'flex-col' : 'flex-row')
      : [
          direction.base === 'col' ? 'flex-col' : (direction.base === 'row' ? 'flex-row' : ''),
          direction.md === 'col' ? 'md:flex-col' : (direction.md === 'row' ? 'md:flex-row' : ''),
          direction.lg === 'col' ? 'lg:flex-col' : (direction.lg === 'row' ? 'lg:flex-row' : ''),
        ].filter(Boolean).join(' '),
    getGapClasses(gap) || 'gap-4',
    wrap ? 'flex-wrap' : '',
    getSpacingClass('m', m),
    getSpacingClass('mt', mt),
    getSpacingClass('mb', mb),
    getSpacingClass('ml', ml),
    getSpacingClass('mr', mr),
    getSpacingClass('p', p),
    getSpacingClass('pt', pt),
    getSpacingClass('pb', pb),
    getSpacingClass('pl', pl),
    getSpacingClass('pr', pr),
    getSpacingClass('px', px),
    getSpacingClass('py', py),
    rounded ? roundedClasses[rounded] : '',
    className
  ].filter(Boolean).join(' ');

  const getAlignItemsClass = (value: StackProps<ElementType>['align']) => {
    if (!value) return '';
    const map: Record<string, string> = { start: 'items-start', center: 'items-center', end: 'items-end', stretch: 'items-stretch', baseline: 'items-baseline' };
    if (typeof value === 'object') {
      const classes = [];
      if (value.base) classes.push(map[value.base]);
      if (value.sm) classes.push(`sm:${map[value.sm]}`);
      if (value.md) classes.push(`md:${map[value.md]}`);
      if (value.lg) classes.push(`lg:${map[value.lg]}`);
      if (value.xl) classes.push(`xl:${map[value.xl]}`);
      if (value['2xl']) classes.push(`2xl:${map[value['2xl']]}`);
      return classes.join(' ');
    }
    return map[value];
  };

  const getJustifyContentClass = (value: StackProps<ElementType>['justify']) => {
    if (!value) return '';
    const map: Record<string, string> = { start: 'justify-start', center: 'justify-center', end: 'justify-end', between: 'justify-between', around: 'justify-around' };
    if (typeof value === 'object') {
      const classes = [];
      if (value.base) classes.push(map[value.base]);
      if (value.sm) classes.push(`sm:${map[value.sm]}`);
      if (value.md) classes.push(`md:${map[value.md]}`);
      if (value.lg) classes.push(`lg:${map[value.lg]}`);
      if (value.xl) classes.push(`xl:${map[value.xl]}`);
      if (value['2xl']) classes.push(`2xl:${map[value['2xl']]}`);
      return classes.join(' ');
    }
    return map[value];
  };

  const layoutClasses = [
    getAlignItemsClass(align),
    getJustifyContentClass(justify)
  ].filter(Boolean).join(' ');

  return (
    <Box 
      as={as} 
      className={`${classes} ${layoutClasses}`}
      w={w}
      h={h}
      minWidth={minWidth}
      maxWidth={maxWidth}
      minHeight={minHeight}
      maxHeight={maxHeight}
      flex={flex}
      flexGrow={flexGrow}
      flexShrink={flexShrink}
      alignSelf={alignSelf}
      {...props}
    >
      {children}
    </Box>
  );
}
