import * as React from 'react';
import { ChevronDown } from 'lucide-react';
import { cn } from '@/lib/utils';

/**
 * AccordionProps - Properties for the Accordion component
 *
 * @interface AccordionProps
 * @extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'>
 */
export interface AccordionProps
  extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
  /**
   * Type of accordion behavior
   * - "single": Only one item can be open at a time
   * - "multiple": Multiple items can be open at the same time
   * @default "single"
   */
  type?: 'single' | 'multiple';

  /**
   * Controlled value(s) of open items
   * For type="single": string | undefined
   * For type="multiple": string[]
   */
  value?: string | string[];

  /**
   * Default value(s) for uncontrolled mode
   * For type="single": string | undefined
   * For type="multiple": string[]
   */
  defaultValue?: string | string[];

  /**
   * Callback when open items change
   * @param value - New value(s) of open items
   */
  onValueChange?: (value: string | string[]) => void;

  /**
   * Children (AccordionItem components)
   */
  children: React.ReactNode;

  /**
   * Whether to allow all items to be closed
   * @default true
   */
  collapsible?: boolean;
}

/**
 * Accordion - Collapsible content sections component
 *
 * A component for displaying collapsible content sections.
 * Supports both single (only one open) and multiple (multiple open) modes.
 *
 * @example
 * ```tsx
 * // Single mode (default)
 * <Accordion type="single" defaultValue="item-1">
 *   <AccordionItem value="item-1">
 *     <AccordionTrigger>Section 1</AccordionTrigger>
 *     <AccordionContent>Content 1</AccordionContent>
 *   </AccordionItem>
 *   <AccordionItem value="item-2">
 *     <AccordionTrigger>Section 2</AccordionTrigger>
 *     <AccordionContent>Content 2</AccordionContent>
 *   </AccordionItem>
 * </Accordion>
 * ```
 *
 * @example
 * ```tsx
 * // Multiple mode
 * <Accordion type="multiple" defaultValue={["item-1", "item-2"]}>
 *   <AccordionItem value="item-1">
 *     <AccordionTrigger>Section 1</AccordionTrigger>
 *     <AccordionContent>Content 1</AccordionContent>
 *   </AccordionItem>
 * </Accordion>
 * ```
 *
 * @component
 */
const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
  (
    {
      type = 'single',
      value: controlledValue,
      defaultValue,
      onValueChange,
      collapsible = true,
      className,
      children,
      ...props
    },
    ref,
  ) => {
    const [internalValue, setInternalValue] = React.useState<
      string | string[]
    >(() => {
      if (type === 'multiple') {
        return (defaultValue as string[]) || [];
      }
      return (defaultValue as string) || '';
    });

    const currentValue =
      controlledValue !== undefined ? controlledValue : internalValue;

    const handleValueChange = (itemValue: string) => {
      if (type === 'single') {
        const newValue = currentValue === itemValue ? '' : itemValue;
        if (!collapsible && newValue === '') {
          return; // Don't allow closing if collapsible is false
        }
        if (controlledValue === undefined) {
          setInternalValue(newValue);
        }
        onValueChange?.(newValue);
      } else {
        const currentArray = (currentValue as string[]) || [];
        const newValue = currentArray.includes(itemValue)
          ? currentArray.filter((v) => v !== itemValue)
          : [...currentArray, itemValue];
        if (controlledValue === undefined) {
          setInternalValue(newValue);
        }
        onValueChange?.(newValue);
      }
    };

    const isItemOpen = (itemValue: string): boolean => {
      if (type === 'single') {
        return currentValue === itemValue;
      }
      return (currentValue as string[]).includes(itemValue);
    };

    return (
      <div ref={ref} className={cn('w-full', className)} {...props}>
        {React.Children.map(children, (child) => {
          if (React.isValidElement(child) && child.type === AccordionItem) {
            return React.cloneElement(child, {
              open: isItemOpen(child.props.value),
              onToggle: handleValueChange,
            } as any);
          }
          return child;
        })}
      </div>
    );
  },
);
Accordion.displayName = 'Accordion';

/**
 * AccordionItemProps - Properties for AccordionItem component
 *
 * @interface AccordionItemProps
 * @extends React.HTMLAttributes<HTMLDivElement>
 */
export interface AccordionItemProps
  extends React.HTMLAttributes<HTMLDivElement> {
  /**
   * Unique value for this accordion item
   */
  value: string;

  /**
   * Whether this item is open (passed automatically by Accordion)
   * @internal
   */
  open?: boolean;

  /**
   * Callback when item is toggled (passed automatically by Accordion)
   * @internal
   */
  onToggle?: (value: string) => void;

  /**
   * Children (AccordionTrigger and AccordionContent)
   */
  children: React.ReactNode;
}

/**
 * AccordionItem - Container for a single accordion section
 *
 * @component
 */
const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
  ({ value, open, onToggle, className, children, ...props }, ref) => {
    return (
      <div
        ref={ref}
        className={cn('border-b border-kodo-steel/30', className)}
        {...props}
      >
        {React.Children.map(children, (child) => {
          if (React.isValidElement(child)) {
            if (child.type === AccordionTrigger) {
              return React.cloneElement(child, {
                open,
                onToggle: () => onToggle?.(value),
              } as any);
            }
            if (child.type === AccordionContent) {
              return React.cloneElement(child, {
                open,
              } as any);
            }
          }
          return child;
        })}
      </div>
    );
  },
);
AccordionItem.displayName = 'AccordionItem';

/**
 * AccordionTriggerProps - Properties for AccordionTrigger component
 *
 * @interface AccordionTriggerProps
 * @extends React.ButtonHTMLAttributes<HTMLButtonElement>
 */
export interface AccordionTriggerProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  /**
   * Whether the item is open (passed automatically by AccordionItem)
   * @internal
   */
  open?: boolean;

  /**
   * Callback when trigger is clicked (passed automatically by AccordionItem)
   * @internal
   */
  onToggle?: () => void;

  /**
   * Children (trigger content)
   */
  children: React.ReactNode;
}

/**
 * AccordionTrigger - Clickable header for accordion item
 *
 * @component
 */
const AccordionTrigger = React.forwardRef<
  HTMLButtonElement,
  AccordionTriggerProps
>(({ open, onToggle, className, children, ...props }, ref) => {
  return (
    <button
      ref={ref}
      type="button"
      onClick={onToggle}
      className={cn(
        'flex w-full items-center justify-between py-4 text-left font-medium transition-all',
        'hover:text-kodo-cyan focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void',
        '[&[data-state=open]>svg]:rotate-180',
        className,
      )}
      aria-expanded={open}
      data-state={open ? 'open' : 'closed'}
      {...props}
    >
      {children}
      <ChevronDown
        className={cn(
          'h-4 w-4 shrink-0 text-kodo-secondary transition-transform duration-200',
          open && 'rotate-180',
        )}
      />
    </button>
  );
});
AccordionTrigger.displayName = 'AccordionTrigger';

/**
 * AccordionContentProps - Properties for AccordionContent component
 *
 * @interface AccordionContentProps
 * @extends React.HTMLAttributes<HTMLDivElement>
 */
export interface AccordionContentProps
  extends React.HTMLAttributes<HTMLDivElement> {
  /**
   * Whether the item is open (passed automatically by AccordionItem)
   * @internal
   */
  open?: boolean;

  /**
   * Children (content to display when open)
   */
  children: React.ReactNode;
}

/**
 * AccordionContent - Content area for accordion item
 *
 * @component
 */
const AccordionContent = React.forwardRef<
  HTMLDivElement,
  AccordionContentProps
>(({ open, className, children, ...props }, ref) => {
  return (
    <div
      ref={ref}
      className={cn(
        'overflow-hidden text-sm transition-all duration-300 ease-in-out',
        open
          ? 'max-h-[5000px] opacity-100'
          : 'max-h-0 opacity-0',
        className,
      )}
      aria-hidden={!open}
      {...props}
    >
      <div className="pb-4 pt-0">{children}</div>
    </div>
  );
});
AccordionContent.displayName = 'AccordionContent';

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
