import { Form, Typography } from 'antd';
import type { FormItemProps } from 'antd';
import type { ReactElement, ReactNode } from 'react';
import { cloneElement, isValidElement } from 'react';
import './FormField.css';

const { Text } = Typography;

export type FormFieldRenderState = {
  disabled?: boolean;
  status?: 'error' | 'warning';
  required?: boolean;
};

export type FormFieldProps = Omit<FormItemProps, 'children' | 'help' | 'required'> & {
  label: ReactNode;
  required?: boolean;
  help?: ReactNode;
  error?: ReactNode;
  disabled?: boolean;
  children: ReactNode | ((state: FormFieldRenderState) => ReactNode);
};

function renderChild(
  children: FormFieldProps['children'],
  state: FormFieldRenderState,
) {
  if (typeof children === 'function') {
    return children(state);
  }

  if (!isValidElement(children)) {
    return children;
  }

  const child = children as ReactElement<Record<string, unknown>>;

  return cloneElement(child, {
    disabled: child.props.disabled ?? state.disabled,
    status: child.props.status ?? state.status,
  });
}

export function FormField({
  label,
  required,
  help,
  error,
  disabled,
  children,
  validateStatus,
  extra,
  className,
  ...restProps
}: FormFieldProps) {
  const status = error ? 'error' : validateStatus;
  const childStatus = status === 'error' || status === 'warning' ? status : undefined;
  const mergedClassName = [
    'form-field',
    disabled ? 'form-field--disabled' : '',
    className ?? '',
  ]
    .filter(Boolean)
    .join(' ');

  return (
    <Form.Item
      {...restProps}
      className={mergedClassName}
      label={label}
      required={required}
      validateStatus={status}
      help={error ?? help}
      extra={
        extra ? (
          extra
        ) : required ? (
          <Text type="secondary">필수 입력 항목입니다.</Text>
        ) : undefined
      }
    >
      {renderChild(children, {
        disabled,
        status: childStatus,
        required,
      })}
    </Form.Item>
  );
}
