"use client";

import type { SubscribableForm } from "@/components/form-common/types";
import type { Label } from "@/components/ui/label";
import type { RadioGroup } from "@/components/ui/radio-group";
import type { Select } from "@/components/ui/select";
import { getErrorMessage } from "@/lib/errors";
import { cn } from "@/lib/utils";
import { FieldApi } from "@tanstack/react-form";
import { shallow } from "@tanstack/react-store";
import {
  type ChangeEvent,
  type ComponentProps,
  useEffect,
  useRef,
} from "react";

export type FieldItemProps = Partial<ReturnType<typeof fieldItemProps>>;
export type FormInputProps = Partial<ReturnType<typeof formInputProps>>;
export type FormSelectProps<
  Data extends string | undefined = string | undefined,
> = Partial<ReturnType<typeof formSelectProps<Data>>>;
export type FormRadioGroupProps = Partial<
  ReturnType<typeof formRadioGroupProps>
>;
export type ControlledFieldItem = {
  fieldApi?: FieldApi<
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >;
};

export function useSubscribeChanges<Data>(
  formApi: SubscribableForm<{ values: Data }>,
  onChange?: (data: Data) => void
) {
  const onChangeRef = useRef(onChange);

  useEffect(() => {
    onChangeRef.current = onChange;
  });

  useEffect(() => {
    onChangeRef.current?.(formApi.state.values);
    return formApi.store.subscribe((state) => {
      if (!shallow(state.currentVal.values, state.prevVal.values)) {
        onChangeRef.current?.(state.currentVal.values);
      }
    });
  }, [formApi]);
}

export function fieldLabelProps(
  field: FieldApi<
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >,
  id: string = "form"
): ComponentProps<typeof Label> {
  const hasError = field.state.meta.errors.length > 0;

  return {
    className: hasError ? "text-destructive" : undefined,
    htmlFor: `${id}:${field.name}`,
  };
}

export function fieldItemProps(
  field: FieldApi<
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >,
  id: string = "form",
  /**
   * @deprecated
   */
  className?: string
) {
  const hasError = field.state.meta.errors.length > 0;

  return {
    id: `${id}:${field.name}`,
    className: cn(hasError ? "ring-destructive!" : undefined, className),
    "aria-invalid": field.state.meta.errors.length > 0,
    "aria-describedby": `${id}:${field.name}:${hasError ? "message" : "description"}`,
  } satisfies ComponentProps<"div">;
}

export function fieldMessageProps(
  field: FieldApi<
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >,
  id: string = "form"
) {
  const hasError = field.state.meta.errors.length > 0;
  const firstError = getErrorMessage(field.state.meta.errors[0]);

  return {
    id: `${id}:${field.name}:message`,
    className: cn(
      "text-sm font-medium text-destructive",
      !hasError && "hidden"
    ),
    "aria-hidden": !hasError,
    children: firstError,
  } satisfies ComponentProps<"p">;
}

export function fieldDescriptionProps(
  field: FieldApi<
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >,
  id: string = "form"
) {
  return {
    id: `${id}:${field.name}:description`,
    className: "text-sm text-muted-frontend",
  };
}

export function formInputProps(
  field: FieldApi<
    any,
    any,
    string,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >,
  disabled?: boolean
) {
  return {
    value: field.state.value ?? "",
    name: field.name,
    onChange: (
      event: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLTextAreaElement>
    ) => {
      field.handleChange(event.target.value);
    },
    onBlur: field.handleBlur,
    disabled: field.form.state.isSubmitting || disabled,
    type: "text",
    "aria-disabled": disabled,
  };
}

export function formSelectProps<Data extends string | undefined>(
  field: FieldApi<
    any,
    any,
    Data,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >,
  disabled?: boolean
) {
  return {
    value: field.state.value ?? "",
    name: field.name,
    onValueChange: (value) =>
      field.handleChange(value === "" ? undefined : (value as any)),
    onOpenChange: (open) => {
      if (!open) {
        field.handleBlur();
      }
    },
    disabled: field.form.state.isSubmitting || disabled,
  } satisfies ComponentProps<typeof Select>;
}

export function formRadioGroupProps<Data extends string | undefined>(
  field: FieldApi<
    any,
    any,
    Data,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >,
  disabled?: boolean
) {
  return {
    value: field.state.value ?? "",
    name: field.name,
    onValueChange: (value) =>
      field.handleChange(value === "" ? undefined : (value as any)),
    disabled: field.form.state.isSubmitting || disabled,
  } satisfies ComponentProps<typeof RadioGroup>;
}
