import {
  createContext,
  forwardRef,
  useContext,
  type ComponentPropsWithoutRef
} from "react";

import {
  inputGroupAffixVariants,
  inputGroupVariants
} from "./input-group.variants";
import { cn } from "../lib/cn";
import type { VariantProps } from "../lib/cva";
import type { FieldStateProps } from "../lib/contracts";
import { createDataAttributes, createSlot } from "../lib/contracts";
import { useFieldContext } from "./field";

type InputGroupContextValue = {
  disabled: boolean;
  invalid: boolean;
  readOnly: boolean;
  required: boolean;
  size: Exclude<VariantProps<typeof inputGroupVariants>["size"], null | undefined>;
};

const InputGroupContext = createContext<InputGroupContextValue | null>(null);

export function useInputGroupContext() {
  return useContext(InputGroupContext);
}

export type InputGroupProps = ComponentPropsWithoutRef<"div"> &
  FieldStateProps &
  VariantProps<typeof inputGroupVariants>;

export const InputGroup = forwardRef<HTMLDivElement, InputGroupProps>(function InputGroup(
  {
    className,
    disabled,
    invalid,
    readOnly,
    required,
    size = "md",
    ...props
  },
  ref
) {
  const field = useFieldContext();
  const resolvedDisabled = disabled ?? field?.disabled ?? false;
  const resolvedInvalid = invalid ?? field?.invalid ?? false;
  const resolvedReadOnly = readOnly ?? field?.readOnly ?? false;
  const resolvedRequired = required ?? field?.required ?? false;
  const resolvedSize = size ?? "md";

  return (
    <InputGroupContext.Provider
      value={{
        disabled: resolvedDisabled,
        invalid: resolvedInvalid,
        readOnly: resolvedReadOnly,
        required: resolvedRequired,
        size: resolvedSize
      }}
    >
      <div
        {...props}
        {...createSlot("control")}
        {...createDataAttributes({
          disabled: resolvedDisabled,
          invalid: resolvedInvalid,
          readonly: resolvedReadOnly,
          required: resolvedRequired,
          size: resolvedSize
        })}
        className={cn(inputGroupVariants({ size: resolvedSize }), className)}
        ref={ref}
      />
    </InputGroupContext.Provider>
  );
});

export type InputGroupPrefixProps = ComponentPropsWithoutRef<"div">;

export const InputGroupPrefix = forwardRef<HTMLDivElement, InputGroupPrefixProps>(
  function InputGroupPrefix({ className, ...props }, ref) {
    return (
      <div
        {...props}
        {...createSlot("prefix")}
        className={cn(inputGroupAffixVariants(), className)}
        ref={ref}
      />
    );
  }
);

export type InputGroupSuffixProps = ComponentPropsWithoutRef<"div">;

export const InputGroupSuffix = forwardRef<HTMLDivElement, InputGroupSuffixProps>(
  function InputGroupSuffix({ className, ...props }, ref) {
    return (
      <div
        {...props}
        {...createSlot("suffix")}
        className={cn(inputGroupAffixVariants(), className)}
        ref={ref}
      />
    );
  }
);
