import { cn } from "@/lib/utils";
import { FormControl, FormDescription, FormField, FormItem, InputProps } from "@/ui";
import { CurrencyData, MoneyValue } from "@shared/contexts";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import CurrencyInput from "react-currency-input-field";
import { FieldPath, FieldValues, UseControllerProps, useFormContext } from "react-hook-form";
import { FormErrorMessage } from "./FormErrorMessage";
import { FormLabel, FormLabelProps } from "./FormLabel";
import { FormInputProps, FormInputWithIconProps } from "./FormProps";

const formCurrencyFieldVariants = cva(
  "flex h-10 w-full rounded-md bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
  {
    variants: {
      variant: {
        default:
          "border border-input ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ",
        outline: "focus-visible:border focus-visible:border-input",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
);

export type FormCurrencyFieldProps<
  TFieldValues extends FieldValues = FieldValues,
  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> = {
  button?: (props?: React.PropsWithChildren) => React.ReactNode;
  defaultValue?: any;
} & InputProps &
  FormInputProps &
  Partial<FormLabelProps> &
  FormInputWithIconProps &
  UseControllerProps<TFieldValues, TName> &
  VariantProps<typeof formCurrencyFieldVariants> & {
    currency: CurrencyData;
    precision: number;
  };

export const FormCurrencyField = React.forwardRef<HTMLInputElement, FormCurrencyFieldProps>(
  (props, ref) => {
    const {
      name,
      label,
      hint,
      description,
      placeholder,
      className,
      disabled,
      defaultValue,
      rules,
      readOnly,
      precision,
      currency,
      variant,
    } = props;

    const { control } = useFormContext();

    const transform = {
      input: (value: any) => {
        if (typeof value !== "object") {
          return value;
        }

        const moneyOrError = MoneyValue.create(value);
        if (moneyOrError.isFailure) {
          throw moneyOrError.error;
        }

        return moneyOrError.object
          .convertPrecision(precision ?? value.precision)
          .toUnit()
          .toString();
      },

      output: (value: string | undefined) => {
        const moneyOrError = MoneyValue.create({
          amount: value?.replace(",", "") ?? null,
          precision,
          currencyCode: currency.code,
        });
        if (moneyOrError.isFailure) {
          throw moneyOrError.error;
        }

        return moneyOrError.object.toObject();
      },
    };

    return (
      <FormField
        defaultValue={defaultValue}
        control={control}
        name={name}
        disabled={disabled}
        rules={rules}
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        render={({ field, fieldState, formState }) => {
          return (
            <FormItem ref={ref} className={cn(className, "space-y-3")}>
              {label && (
                <FormLabel label={label} hint={hint} required={Boolean(rules?.required ?? false)} />
              )}
              <FormControl>
                <CurrencyInput
                  name={field.name}
                  //ref={field.ref} <-- no activar que hace cosas raras
                  onBlur={field.onBlur}
                  disabled={field.disabled}
                  readOnly={readOnly}
                  className={cn(formCurrencyFieldVariants({ variant, className }))}
                  suffix={` ${currency?.symbol}`}
                  groupSeparator='.'
                  decimalSeparator=','
                  placeholder={placeholder}
                  //fixedDecimalLength={precision} <- no activar para que sea más cómodo escribir las cantidades
                  decimalsLimit={precision}
                  decimalScale={precision}
                  value={transform.input(field.value)}
                  onValueChange={(e) => field.onChange(transform.output(e))}
                />
              </FormControl>
              {description && <FormDescription>{description}</FormDescription>}
              <FormErrorMessage />
            </FormItem>
          );
        }}
      />
    );
  }
);

FormCurrencyField.displayName = "FormCurrencyField";
