import * as React from "react";

function mergeRefs<T>(
  ...refs: (React.Ref<T> | undefined | null)[]
): (value: T | null) => void {
  return (value: T | null): void => {
    for (const ref of refs) {
      if (typeof ref === "function") ref(value);
      else if (ref !== null)
        (ref as React.MutableRefObject<T | null>).current = value;
    }
  };
}

interface SlotProps extends React.HTMLAttributes<HTMLElement> {
  children?: React.ReactNode;
}

const Slot = React.forwardRef<HTMLElement, SlotProps>(
  ({ children, ...props }, forwardedRef) => {
    const child = React.Children.only(children);
    if (!React.isValidElement(child)) return null;

    const childProps = child.props as Record<string, unknown>;
    const merged: Record<string, unknown> = { ...props };

    for (const key of Object.keys(childProps)) {
      if (key === "className") {
        merged.className = [props.className, childProps.className]
          .filter(Boolean)
          .join(" ");
      } else if (key === "style") {
        merged.style = {
          ...(props.style as object),
          ...(childProps.style as object),
        };
      } else if (
        key.startsWith("on") &&
        typeof childProps[key] === "function"
      ) {
        const parentHandler = (props as Record<string, unknown>)[key];
        if (typeof parentHandler === "function") {
          merged[key] = (...args: unknown[]) => {
            (childProps[key] as (...a: unknown[]) => unknown)(...args);
            (parentHandler as (...a: unknown[]) => unknown)(...args);
          };
        } else {
          merged[key] = childProps[key];
        }
      } else {
        merged[key] = childProps[key];
      }
    }

    const childRef = (child as unknown as { ref?: React.Ref<HTMLElement> }).ref;
    merged.ref = forwardedRef
      ? mergeRefs(forwardedRef, childRef)
      : childRef;

    return React.cloneElement(
      child,
      merged as React.Attributes & Record<string, unknown>,
    );
  },
);
Slot.displayName = "Slot";

export { Slot };
