'use client';

import { Form as RadixForm } from 'radix-ui';
import React from 'react';
import { FormContext } from './context';
import { getByPath, setByPath, validateRule } from './utils';
import type { FormProps, FormAction, FormContextValue, Rules } from './types';

const FormComponent = <
  TValues extends Record<string, any> = Record<string, any>,
>(
  props: FormProps<TValues>,
  ref: React.Ref<FormAction<TValues>>
) => {
  const {
    initialValues,
    onSubmit = () => {},
    onChange,
    combineValidate,
    loading = false,
    disabled = false,
    children,
  } = props;

  // 使用 ref 存储表单值，避免触发全局重新渲染
  const valuesRef = React.useRef<TValues>((initialValues || {}) as TValues);

  // 使用 ref 存储表单错误
  const errorsRef = React.useRef<Record<string, string>>({});

  // 用于强制更新错误的 state（只有错误变化时才触发重新渲染）
  const [errorsVersion, setErrorsVersion] = React.useState(0);

  // 字段订阅器（用于性能优化）
  const valueSubscribersRef = React.useRef<Record<string, Set<() => void>>>({});
  const errorSubscribersRef = React.useRef<Record<string, Set<() => void>>>({});

  // 提交状态
  const [isSubmitting, setIsSubmitting] = React.useState(false);

  // 表单引用（用于原生表单提交）
  const formRef = React.useRef<HTMLFormElement>(null);

  // 字段规则映射（由 FormItem 注册）
  const fieldRulesRef = React.useRef<Record<string, Rules>>({});

  // 注册字段规则（供 FormItem 使用）
  const registerFieldRules = React.useCallback((name: string, rules: Rules) => {
    fieldRulesRef.current[name] = rules;
  }, []);

  // 订阅字段值变化
  const subscribe = React.useCallback((name: string, callback: () => void) => {
    if (!valueSubscribersRef.current[name]) {
      valueSubscribersRef.current[name] = new Set();
    }
    valueSubscribersRef.current[name].add(callback);

    // 返回取消订阅函数
    return () => {
      valueSubscribersRef.current[name]?.delete(callback);
    };
  }, []);

  // 通知字段值订阅者
  const notifyValueSubscribers = React.useCallback((name: string) => {
    valueSubscribersRef.current[name]?.forEach((callback) => callback());
  }, []);

  // 通知字段错误订阅者
  const notifyErrorSubscribers = React.useCallback((name: string) => {
    errorSubscribersRef.current[name]?.forEach((callback) => callback());
  }, []);

  // 订阅字段错误变化
  const subscribeError = React.useCallback(
    (name: string, callback: () => void) => {
      if (!errorSubscribersRef.current[name]) {
        errorSubscribersRef.current[name] = new Set();
      }
      errorSubscribersRef.current[name].add(callback);

      return () => {
        errorSubscribersRef.current[name]?.delete(callback);
      };
    },
    []
  );

  // 组合订阅函数（同时订阅值和错误变化），使用 useCallback 确保引用稳定
  const subscribeField = React.useCallback(
    (name: string, callback: () => void) => {
      // 同时订阅值和错误的变化
      const unsubscribeValue = subscribe(name, callback);
      const unsubscribeError = subscribeError(name, callback);
      return () => {
        unsubscribeValue();
        unsubscribeError();
      };
    },
    [subscribe, subscribeError]
  );

  // 设置字段值
  const setFieldValue = React.useCallback(
    (name: string, value: any) => {
      setByPath(valuesRef.current, name, value);

      // 通知订阅该字段的组件
      notifyValueSubscribers(name);

      // 触发 onChange 回调
      if (onChange) {
        onChange({ ...valuesRef.current });
      }
    },
    [onChange, notifyValueSubscribers]
  );

  // 获取字段值（从 ref 读取，不触发重新渲染）
  const getFieldValue = React.useCallback((name: string) => {
    return getByPath(valuesRef.current, name);
  }, []);

  // 设置字段错误
  const setFieldError = React.useCallback(
    (name: string, error: string | undefined) => {
      if (error) {
        errorsRef.current[name] = error;
      } else {
        delete errorsRef.current[name];
      }

      // 更新错误版本号，触发重新渲染
      setErrorsVersion((prev) => prev + 1);

      // 通知订阅该字段错误的组件
      notifyErrorSubscribers(name);
    },
    [notifyErrorSubscribers]
  );

  // 获取字段错误
  const getFieldError = React.useCallback((name: string) => {
    return errorsRef.current[name];
  }, []);

  // 校验单个字段
  const validateField = React.useCallback(
    async (name: string): Promise<boolean> => {
      const rules = fieldRulesRef.current[name];
      if (!rules || rules.length === 0) {
        setFieldError(name, undefined);
        return true;
      }

      const value = getFieldValue(name);
      const currentValues = { ...valuesRef.current };

      // 依次校验每个规则
      for (const rule of rules) {
        const error = await validateRule(rule, value, currentValues);
        if (error) {
          setFieldError(name, error);
          return false;
        }
      }

      // 所有规则都通过
      setFieldError(name, undefined);
      return true;
    },
    [getFieldValue, setFieldError]
  );

  // 校验所有字段
  const validateAll = React.useCallback(async (): Promise<boolean> => {
    const fieldNames = Object.keys(fieldRulesRef.current);
    const results = await Promise.all(
      fieldNames.map((name) => validateField(name))
    );

    // 如果所有字段校验都通过，再进行组合校验
    if (results.every((result) => result === true) && combineValidate) {
      const combineResult = await combineValidate(valuesRef.current);
      if (combineResult) {
        // 组合校验失败，设置错误到指定字段
        setFieldError(combineResult.key, combineResult.message);
        return false;
      }
    }

    return results.every((result) => result === true);
  }, [validateField, combineValidate, setFieldError]);

  // 获取所有表单值
  const getValues = React.useCallback(() => {
    return { ...valuesRef.current };
  }, []);

  // 重置表单
  const reset = React.useCallback(
    (newValues?: Partial<TValues>) => {
      valuesRef.current = (newValues || initialValues || {}) as TValues;
      errorsRef.current = {};
      setErrorsVersion((prev) => prev + 1);

      // 通知所有订阅者
      Object.keys(valueSubscribersRef.current).forEach((name) => {
        notifyValueSubscribers(name);
      });
      Object.keys(errorSubscribersRef.current).forEach((name) => {
        notifyErrorSubscribers(name);
      });
    },
    [initialValues, notifyValueSubscribers, notifyErrorSubscribers]
  );

  // 暴露 ref 方法
  React.useImperativeHandle(
    ref,
    (): FormAction<TValues> => ({
      validateFields: async () => {
        const isValid = await validateAll();
        return isValid ? getValues() : null;
      },
      getValues,
      reset,
      setFieldValue,
      setFieldError,
    }),
    [validateAll, getValues, reset, setFieldValue, setFieldError]
  );

  // 表单提交处理
  const handleSubmit = React.useCallback(
    async (event: React.FormEvent<HTMLFormElement>) => {
      event.preventDefault();

      if (loading || isSubmitting) return;

      // 校验所有字段（包括组合校验）
      const isValid = await validateAll();
      if (!isValid) {
        return;
      }

      try {
        setIsSubmitting(true);
        await onSubmit(valuesRef.current);
      } catch (error) {
        console.error('Form submission error:', error);
      } finally {
        setIsSubmitting(false);
      }
    },
    [validateAll, onSubmit, loading, isSubmitting]
  );

  // Context 值
  const contextValue = React.useMemo<FormContextValue<TValues>>(
    () => ({
      valuesRef,
      errorsRef,
      setFieldValue,
      getFieldValue,
      setFieldError,
      getFieldError,
      validateField,
      validateAll,
      getValues,
      reset,
      disabled: disabled || loading || isSubmitting,
      registerFieldRules,
      subscribe: subscribeField,
    }),
    [
      setFieldValue,
      getFieldValue,
      setFieldError,
      getFieldError,
      validateField,
      validateAll,
      getValues,
      reset,
      disabled,
      loading,
      isSubmitting,
      registerFieldRules,
      subscribeField,
      // 移除 errorsVersion，避免错误变化时导致所有 FormItem 重新渲染
      // 错误变化已通过订阅机制通知到对应的 FormItem
    ]
  );

  return (
    <FormContext.Provider value={contextValue}>
      <RadixForm.Root ref={formRef} onSubmit={handleSubmit}>
        <fieldset
          disabled={disabled || loading || isSubmitting}
          style={{ border: 'none', padding: 0, margin: 0 }}
        >
          {children}
        </fieldset>
      </RadixForm.Root>
    </FormContext.Provider>
  );
};

export const Form = React.forwardRef(FormComponent) as <
  TValues extends Record<string, any> = Record<string, any>,
>(
  props: FormProps<TValues> & { ref?: React.Ref<FormAction<TValues>> }
) => React.ReactElement;
