import { formHasAnyDirty, pickFormDirtyValues } from "@erp/core/client";
import { useHookForm } from "@erp/core/hooks";
import { showErrorToast, showSuccessToast, showWarningToast } from "@repo/rdx-ui/helpers";
import { useEffect, useId, useMemo } from "react";
import { FieldErrors, FormProvider } from "react-hook-form";
import { useCustomerQuery, useUpdateCustomer } from "../../hooks";
import { useTranslation } from "../../i18n";
import {
  Customer,
  CustomerFormData,
  CustomerFormSchema,
  defaultCustomerFormData,
} from "../../schemas";

export interface UseCustomerUpdateControllerOptions {
  onUpdated?(updated: Customer): void;
  successToasts?: boolean; // mostrar o no toast automáticcamente

  onError?(error: Error, patchData: ReturnType<typeof pickFormDirtyValues>): void;
  errorToasts?: boolean; // mostrar o no toast automáticcamente
}

export const useCustomerUpdateController = (
  customerId?: string,
  options?: UseCustomerUpdateControllerOptions
) => {
  const { t } = useTranslation();
  const formId = useId(); // id único por instancia

  // 1) Estado de carga del cliente (query)
  const {
    data: customerData,
    isLoading,
    isError: isLoadError,
    error: loadError,
  } = useCustomerQuery(customerId, { enabled: Boolean(customerId) });

  // 2) Estado de creación (mutación)
  const {
    mutateAsync,
    isPending: isUpdating,
    isError: isUpdateError,
    error: updateError,
  } = useUpdateCustomer();

  const initialValues = useMemo(() => customerData ?? defaultCustomerFormData, [customerData]);

  // 3) Form hook
  const form = useHookForm<CustomerFormData>({
    resolverSchema: CustomerFormSchema,
    initialValues,
    disabled: isLoading || isUpdating,
  });

  /** Reiniciar el form al recibir datos */
  useEffect(() => {
    // keepDirty = false -> deja el formulario sin cambios sin tener que esperar al siguiente render.
    if (customerData) form.reset(customerData, { keepDirty: false });
  }, [customerData, form]);

  /** Handlers */

  const resetForm = () => form.reset(customerData ?? defaultCustomerFormData);

  // Versión sincronizada
  const submitHandler = form.handleSubmit(
    async (formData) => {
      if (!customerId) {
        showErrorToast(t("pages.update.error.title"), "Falta el ID del cliente");
        return;
      }

      const { dirtyFields } = form.formState;
      if (!formHasAnyDirty(dirtyFields)) {
        showWarningToast(t("pages.update.error.no_changes"), "No hay cambios para guardar");
        return;
      }

      const patchData = pickFormDirtyValues(formData, dirtyFields);
      const previousData = customerData;

      try {
        // Enviamos cambios al servidor
        const updated = await mutateAsync({ id: customerId, data: patchData });

        // Ha ido bien -> actualizamos form con datos reales
        // keepDirty = false -> deja el formulario sin cambios sin tener que esperar al siguiente render.
        form.reset(updated, { keepDirty: false });

        if (options?.successToasts !== false) {
          showSuccessToast(
            t("pages.update.success.title", "Cliente modificado"),
            t("pages.update.success.message", "Se ha modificado correctamente.")
          );
        }
        options?.onUpdated?.(updated);
      } catch (error: any) {
        // Algo ha fallado -> revertimos cambios
        form.reset(previousData ?? defaultCustomerFormData);
        if (options?.errorToasts !== false) {
          showErrorToast(t("pages.update.error.title"), error.message);
        }
        options?.onError?.(error, patchData);
      }
    },
    (errors: FieldErrors<CustomerFormData>) => {
      const firstKey = Object.keys(errors)[0] as keyof CustomerFormData | undefined;
      if (firstKey) document.querySelector<HTMLElement>(`[name="${String(firstKey)}"]`)?.focus();

      showWarningToast(
        t("forms.validation.title", "Revisa los campos"),
        t("forms.validation.message", "Hay errores de validación en el formulario.")
      );
    }
  );

  // Evento onSubmit ya preparado para el <form>
  const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.stopPropagation(); // <-- evita que el submit se propage por los padre en el árbol DOM
    submitHandler(event);
  };

  return {
    // form
    form,
    formId,

    // handlers del form
    onSubmit,
    resetForm,

    // carga de datos
    customerData,
    isLoading,
    isLoadError,
    loadError,

    // mutation
    isUpdating,
    isUpdateError,
    updateError,

    // Por comodidad
    FormProvider,
  };
};
