"use client";

import { type ComponentType, type HTMLAttributes, type Ref, createContext, useContext } from "react";
import { HelpCircle, InfoCircle } from "@untitledui/icons";
import type { InputProps as AriaInputProps, TextFieldProps as AriaTextFieldProps } from "react-aria-components";
import { Group as AriaGroup, Input as AriaInput, TextField as AriaTextField } from "react-aria-components";
import { HintText } from './hint-text';
import { Label } from './label';
import { Tooltip, TooltipTrigger } from '../tooltip/tooltip';
import { cx, sortCx } from '../../../utils/cx';

export interface InputBaseProps extends AriaTextFieldProps {
    tooltip?: string;
    size?: "sm" | "md";
    placeholder?: string;
    iconClassName?: string;
    inputClassName?: string;
    wrapperClassName?: string;
    tooltipClassName?: string;
    shortcut?: string | boolean;
    ref?: Ref<HTMLInputElement>;
    groupRef?: Ref<HTMLDivElement>;
    icon?: ComponentType<HTMLAttributes<HTMLOrSVGElement>>;
    label?: string;
    hint?: string;
}

const TextFieldContext = createContext<Partial<InputBaseProps>>({});

export const InputBase = ({
    ref,
    tooltip,
    shortcut,
    groupRef,
    size = "sm",
    isInvalid,
    isDisabled,
    icon: Icon,
    placeholder,
    wrapperClassName,
    tooltipClassName,
    inputClassName,
    iconClassName,
    ...inputProps
}: Omit<InputBaseProps, "label" | "hint" | "isRequired">) => {
    const hasTrailingIcon = tooltip || isInvalid;
    const hasLeadingIcon = Icon;
    const context = useContext(TextFieldContext);
    const inputSize = context?.size || size;

    const sizes = sortCx({
        sm: {
            root: cx("px-3 py-2.5", hasTrailingIcon && "pr-9", hasLeadingIcon && "pl-10"),
            iconLeading: "left-3",
            iconTrailing: "right-3",
            shortcut: "pr-2.5",
        },
        md: {
            root: cx("px-3.5 py-3", hasTrailingIcon && "pr-9.5", hasLeadingIcon && "pl-10.5"),
            iconLeading: "left-3.5",
            iconTrailing: "right-3.5",
            shortcut: "pr-3",
        },
    });

    return (
        <AriaGroup
            {...{ isDisabled, isInvalid }}
            ref={groupRef}
            className={({ isFocusWithin, isDisabled, isInvalid }) =>
                cx(
                    "relative flex w-full flex-row place-content-center place-items-center rounded-sm bg-white ring-1 ring-secondary transition-shadow duration-100 ease-linear ring-inset",
                    isFocusWithin && !isDisabled && "ring-2 ring-focus-ring",
                    isDisabled && "cursor-not-allowed bg-primary ring-secondary",
                    isInvalid && "ring-error_subtle",
                    isInvalid && isFocusWithin && "ring-2 ring-error",
                    context?.wrapperClassName,
                    wrapperClassName,
                )
            }
        >
            {Icon && (
                <Icon
                    className={cx(
                        "pointer-events-none absolute size-5 text-secondary",
                        isDisabled && "text-border-secondary",
                        sizes[inputSize].iconLeading,
                        context?.iconClassName,
                        iconClassName,
                    )}
                />
            )}

            <AriaInput
                {...(inputProps as AriaInputProps)}
                ref={ref}
                placeholder={placeholder}
                className={cx(
                    "m-0 w-full bg-transparent text-base font-body text-fg-primary ring-0 outline-hidden placeholder:text-secondary autofill:rounded-sm autofill:text-fg-primary",
                    isDisabled && "cursor-not-allowed text-secondary",
                    sizes[inputSize].root,
                    context?.inputClassName,
                    inputClassName,
                )}
            />

            {tooltip && !isInvalid && (
                <Tooltip title={tooltip} placement="top">
                    <TooltipTrigger
                        className={cx(
                            "absolute cursor-pointer text-secondary transition duration-200 hover:text-fg-primary focus:text-fg-primary",
                            sizes[inputSize].iconTrailing,
                            context?.tooltipClassName,
                            tooltipClassName,
                        )}
                    >
                        <HelpCircle className="size-4" />
                    </TooltipTrigger>
                </Tooltip>
            )}

            {isInvalid && (
                <InfoCircle
                    className={cx(
                        "pointer-events-none absolute size-4 text-error",
                        sizes[inputSize].iconTrailing,
                    )}
                />
            )}

            {shortcut && (
                <kbd
                    className={cx(
                        "pointer-events-none absolute flex h-5 items-center justify-center rounded bg-utility-gray-50 px-1.5 text-xs font-medium text-tertiary shadow-xs ring-1 ring-inset ring-utility-gray-200",
                        sizes[inputSize].shortcut,
                    )}
                >
                    {shortcut === true ? "⌘K" : shortcut}
                </kbd>
            )}
        </AriaGroup>
    );
};

export const Input = ({
    label,
    hint,
    size,
    isInvalid,
    isDisabled,
    isRequired,
    ...props
}: InputBaseProps) => {
    const textFieldContext = { size, wrapperClassName: props.wrapperClassName, inputClassName: props.inputClassName, iconClassName: props.iconClassName, tooltipClassName: props.tooltipClassName };

    return (
        <TextFieldContext.Provider value={textFieldContext}>
            <AriaTextField
                {...({ isInvalid, isDisabled, isRequired } as AriaTextFieldProps)}
                className="flex flex-col gap-1.5"
            >
                {label && <Label>{label}</Label>}
                <InputBase {...props} size={size} isInvalid={isInvalid} isDisabled={isDisabled} />
                {hint && <HintText>{hint}</HintText>}
            </AriaTextField>
        </TextFieldContext.Provider>
    );
};

import { registerThemeVariant } from '../../../lib/component-registry';
registerThemeVariant('input', 'aman', Input);
