import React, { useState, useEffect, useRef } from 'react';
import { cn } from '@/lib/utils';
import FormLabel from './FormLabel';
import FormError from './FormError';

/**
 * FormCheckbox Component
 * Single and group checkboxes with indeterminate state and custom styling
 */

export interface CheckboxOption {
  value: string;
  label: string;
  disabled?: boolean;
}

export interface FormCheckboxProps {
  label?: string;
  error?: string | string[];
  helpText?: string;
  required?: boolean;
  checked?: boolean;
  indeterminate?: boolean;
  options?: CheckboxOption[];
  value?: string[];
  onChange?: (value: string[]) => void;
  containerClassName?: string;
  checkboxClassName?: string;
  disabled?: boolean;
  id?: string;
  name?: string;
}

export const FormCheckbox: React.FC<FormCheckboxProps> = ({
  label,
  error,
  helpText,
  required = false,
  checked = false,
  indeterminate = false,
  options,
  value = [],
  onChange,
  containerClassName,
  checkboxClassName,
  disabled = false,
  id,
  name,
}) => {
  const [internalChecked, setInternalChecked] = useState(checked);
  const checkboxRef = useRef<HTMLInputElement>(null);

  const hasError = !!error;
  const showError = hasError;

  // Handle indeterminate state
  useEffect(() => {
    if (checkboxRef.current) {
      checkboxRef.current.indeterminate = indeterminate;
    }
  }, [indeterminate, internalChecked]);

  // Sync internal state with prop
  useEffect(() => {
    setInternalChecked(checked);
  }, [checked]);

  const isGroup = Array.isArray(options) && options.length > 0;

  const handleSingleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newChecked = e.target.checked;
    setInternalChecked(newChecked);
    if (onChange && !isGroup) {
      // For single checkbox, call onChange with boolean
      // But to maintain consistency, we'll treat it as a group with one option
      if (newChecked) {
        onChange([name || 'checkbox']);
      } else {
        onChange([]);
      }
    }
  };

  const handleGroupChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const optionValue = e.target.value;
    const isChecked = e.target.checked;

    let newValue: string[];

    if (isChecked) {
      newValue = [...value, optionValue];
    } else {
      newValue = value.filter((v) => v !== optionValue);
    }

    if (onChange) {
      onChange(newValue);
    }
  };

  const inputId = id || (label ? label.toLowerCase().replace(/\s+/g, '-') : undefined);

  const baseCheckboxClasses = cn(
    'w-4 h-4 rounded border transition-all duration-200',
    'focus:outline-none focus:ring-2 focus:ring-primary',
    {
      'border-neutral-dark bg-neutral-light': !internalChecked && !hasError && !indeterminate,
      'border-primary bg-primary text-white': internalChecked && !hasError,
      'border-danger bg-danger text-white': hasError,
      'border-primary bg-primary/50 text-white': indeterminate,
      'opacity-60 cursor-not-allowed': disabled,
      'cursor-pointer': !disabled,
    },
    checkboxClassName
  );

  const containerClasses = cn(
    'flex flex-col gap-2',
    containerClassName
  );

  const groupContainerClasses = cn(
    'flex flex-col gap-2',
    containerClassName
  );

  const singleWrapperClasses = cn(
    'flex items-start gap-2',
    {
      'opacity-60': disabled,
    }
  );

  const labelClasses = cn(
    'text-sm font-medium leading-none',
    {
      'text-text-primary': !hasError,
      'text-danger': hasError,
    }
  );

  // Single checkbox
  if (!isGroup) {
    return (
      <div className={containerClasses}>
        <div className={singleWrapperClasses}>
          <input
            ref={checkboxRef}
            type="checkbox"
            id={inputId}
            name={name}
            checked={internalChecked}
            onChange={handleSingleChange}
            disabled={disabled}
            required={required}
            aria-invalid={hasError}
            aria-describedby={helpText || showError ? `${inputId}-error` : undefined}
            className={baseCheckboxClasses}
          />
          
          <div className="flex-1">
            {label && (
              <label htmlFor={inputId} className={labelClasses}>
                {label}
                {required && <span className="text-danger ml-1">*</span>}
              </label>
            )}
            
            {helpText && (
              <p className="text-xs text-text-secondary mt-1" id={`${inputId}-help`}>
                {helpText}
              </p>
            )}
          </div>
        </div>

        {showError && (
          <FormError errors={error} id={`${inputId}-error`} />
        )}
      </div>
    );
  }

  // Checkbox group
  const groupLabelId = inputId ? `${inputId}-group-label` : undefined;
  const allSelected = options.every(opt => value.includes(opt.value));
  const someSelected = options.some(opt => value.includes(opt.value)) && !allSelected;

  // Update indeterminate state for group select all
  useEffect(() => {
    if (checkboxRef.current && someSelected) {
      checkboxRef.current.indeterminate = true;
    }
  }, [someSelected, value, options]);

  return (
    <div className={groupContainerClasses}>
      {label && (
        <div className="mb-2">
          <FormLabel id={groupLabelId} required={required}>
            {label}
          </FormLabel>
        </div>
      )}

      <div className="flex flex-col gap-2" role="group" aria-labelledby={groupLabelId}>
        {options.map((option) => {
          const optionId = `${inputId}-${option.value}`;
          const isChecked = value.includes(option.value);

          return (
            <div key={option.value} className="flex items-start gap-2">
              <input
                type="checkbox"
                id={optionId}
                value={option.value}
                checked={isChecked}
                onChange={handleGroupChange}
                disabled={disabled || option.disabled}
                required={required && value.length === 0}
                aria-invalid={hasError}
                className={cn(
                  baseCheckboxClasses,
                  option.disabled && 'opacity-50'
                )}
              />
              
              <div className="flex-1">
                <label
                  htmlFor={optionId}
                  className={cn(
                    labelClasses,
                    option.disabled && 'opacity-50'
                  )}
                >
                  {option.label}
                </label>
              </div>
            </div>
          );
        })}
      </div>

      {helpText && (
        <p className="text-xs text-text-secondary mt-1" id={`${inputId}-help`}>
          {helpText}
        </p>
      )}

      {showError && (
        <FormError errors={error} id={`${inputId}-error`} />
      )}
    </div>
  );
};

FormCheckbox.displayName = 'FormCheckbox';

export default FormCheckbox;