import React, { useCallback, useId, useMemo, useState } from 'react';
import { cn } from '@/lib/helper';

export type CollapseVariant = 'default' | 'arrow' | 'plus';

export type CollapseProps = {
  /** Unique name used when `asRadio` is true (Accordion single-open). */
  name?: string;
  /** If provided, component is controlled. */
  open?: boolean;
  /** Initial open state for uncontrolled usage. */
  defaultOpen?: boolean;
  /** Callback when open state changes. */
  onOpenChange?: (open: boolean) => void;
  /** Title row content. Accepts string or custom node. */
  title?: React.ReactNode;
  /** Optional secondary text displayed under/next to title. */
  subtitle?: React.ReactNode;
  /** Content of the panel. */
  children?: React.ReactNode;
  /** Visual variant: default / arrow / plus */
  variant?: CollapseVariant;
  /** Add a bordered look */
  bordered?: boolean;
  /** Disable interactions */
  disabled?: boolean;
  /** Allow only one open at a time by switching to radio input */
  asRadio?: boolean;
  /** Force full width instead of auto-fit when collapsed
   * (Khusus justify-between dan justify-end) */
  fullWidth?: boolean;
  /** Extra classnames */
  className?: string;
  titleClassName?: string;
  contentClassName?: string;
};

export const Collapse = ({
  name,
  open,
  defaultOpen,
  onOpenChange,
  title,
  subtitle,
  children,
  variant = 'default',
  bordered,
  disabled,
  asRadio = false,
  fullWidth,
  className,
  titleClassName,
  contentClassName,
}: CollapseProps) => {
  const inputId = useId();
  const isControlled = typeof open === 'boolean';
  const [internalOpen, setInternalOpen] = useState(!!defaultOpen);
  const isOpen = isControlled ? !!open : internalOpen;

  // Manage change from checkbox/radio
  const handleChange = useCallback(
    (next: boolean) => {
      if (!isControlled) setInternalOpen(next);
      onOpenChange?.(next);
    },
    [isControlled, onOpenChange]
  );

  const inputType = asRadio ? 'radio' : 'checkbox';

  const rootClass = cn(
    'collapse',
    variant === 'arrow' && 'collapse-arrow',
    variant === 'plus' && 'collapse-plus',
    bordered && 'border base-content/20 border-opacity-20 rounded-box',
    disabled && 'opacity-60 pointer-events-none',
    !fullWidth && !open && 'w-fit',
    className
  );

  const titleNode = useMemo(() => {
    if (subtitle) {
      return (
        <div className='flex flex-col gap-0.5'>
          <span>{title}</span>
          <span className='text-sm opacity-70'>{subtitle}</span>
        </div>
      );
    }
    return title;
  }, [title, subtitle]);

  return (
    <div className={rootClass} data-open={isOpen}>
      <input
        id={inputId}
        type={inputType}
        name={asRadio ? name : undefined}
        className='peer p-0 hidden'
        checked={isOpen}
        onChange={(e) => handleChange(e.currentTarget.checked)}
        aria-controls={`${inputId}-content`}
        disabled={disabled}
      />

      <div
        role='button'
        tabIndex={0}
        className={cn(
          'collapse-title w-fit p-0',
          'focus:outline-none focus-visible:ring focus-visible:ring-primary/40',
          titleClassName
        )}
        onKeyDown={(e) => {
          if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            handleChange(!isOpen);
          }
        }}
        onClick={() => handleChange(!isOpen)}
      >
        {titleNode}
      </div>

      <div
        id={`${inputId}-content`}
        className={cn('collapse-content p-0!', contentClassName)}
      >
        {children}
      </div>
    </div>
  );
};

export default Collapse;
