// packages/core/src/components/form/form-root.tsx
import type { JSX } from "solid-js";
import { splitProps } from "solid-js";
import { createStore } from "solid-js/store";
import { z } from "zod/v4";
import { FormContextProvider, type FormContextValue } from "./form-context";
import type { FormRootProps } from "./form.props";

export type { FormRootProps };

/**
 * Root form element. Manages field values and errors via a reactive store.
 * Validates on submit (or blur/change when validateOn is set) using the
 * provided Zod v4 schema. Calls onSubmit on success, onValidationError on
 * failure.
 */
export function FormRoot(props: FormRootProps): JSX.Element {
  const [local, rest] = splitProps(props, [
    "schema",
    "onSubmit",
    "onValidationError",
    "disabled",
    "validateOn",
    "children",
  ]);

  const [fieldValues, setFieldValues] = createStore<Record<string, unknown>>({});
  const [errors, setErrors] = createStore<Record<string, string[]>>({});

  const getFieldErrors = (name: string): string[] => errors[name] ?? [];

  const setFieldValue = (name: string, value: unknown): void => {
    setFieldValues(name, value);
  };

  const getFieldValue = (name: string): unknown => fieldValues[name];

  const buildFieldErrors = (schema: z.ZodType, values: Record<string, unknown>): Record<string, string[]> => {
    const result = schema.safeParse(values);
    if (result.success) return {};
    const fieldErrors: Record<string, string[]> = {};
    for (const issue of result.error.issues) {
      const path = issue.path.join(".");
      if (!fieldErrors[path]) fieldErrors[path] = [];
      fieldErrors[path].push(issue.message);
    }
    return fieldErrors;
  };

  const validateField = (name: string): void => {
    if (!local.schema) return;
    const allErrors = buildFieldErrors(local.schema, fieldValues);
    setErrors(name, allErrors[name] ?? []);
  };

  const validateAll = (): boolean => {
    if (!local.schema) return true;
    const fieldErrors = buildFieldErrors(local.schema, fieldValues);
    const hasErrors = Object.keys(fieldErrors).length > 0;
    if (hasErrors) {
      for (const [key, msgs] of Object.entries(fieldErrors)) {
        setErrors(key, msgs);
      }
    } else {
      for (const key of Object.keys(errors)) {
        setErrors(key, []);
      }
    }
    return !hasErrors;
  };

  const handleSubmit: JSX.EventHandlerUnion<HTMLFormElement, SubmitEvent> = (e) => {
    e.preventDefault();
    if (local.schema) {
      const result = local.schema.safeParse(fieldValues);
      if (!result.success) {
        const fieldErrors: Record<string, string[]> = {};
        for (const issue of result.error.issues) {
          const path = issue.path.join(".");
          if (!fieldErrors[path]) fieldErrors[path] = [];
          fieldErrors[path].push(issue.message);
        }
        for (const [key, msgs] of Object.entries(fieldErrors)) {
          setErrors(key, msgs);
        }
        local.onValidationError?.(fieldErrors);
        return;
      }
      for (const key of Object.keys(errors)) {
        setErrors(key, []);
      }
      local.onSubmit?.(result.data as Record<string, unknown>, e);
    } else {
      local.onSubmit?.(fieldValues, e);
    }
  };

  const ctx: FormContextValue = {
    errors: () => errors,
    getFieldErrors,
    setFieldValue,
    getFieldValue,
    validateField,
    validateAll,
    disabled: () => local.disabled ?? false,
    validateOn: () => local.validateOn ?? "submit",
  };

  return (
    <FormContextProvider value={ctx}>
      <form onSubmit={handleSubmit} {...rest}>
        {local.children}
      </form>
    </FormContextProvider>
  );
}
