'use client';

import React, { useEffect, useMemo, useState } from 'react';
import { Text } from '@/components/ui/text';
import { Control, useForm, Path, FieldValues } from 'react-hook-form';
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form';
import { Button } from '@/components/ui/button';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { transformSelectOptions } from '@/utils/transformers';
import { DialogClose } from '@/components/ui/dialog';
import { globalApiPost } from '@/services/global/globalApiCalls';
import {
  DateFieldProps,
  FormFieldRenderer,
  InputFieldProps,
  MultiSelectFieldProps,
  SelectFieldProps,
} from './elements/FormFieldRenderer';
import { FormElement, FormOption } from '@/types/form-types';
import { BucketProp, MixRecord, UnknownRecord, fnBool } from '@/types';
import { prepareAddEditFormDropdown } from '@/utils/prepareAddEditFormDropdown';
import MenuActionItems, { FormDataWithMenuActions } from '../MenuActionItems';
import { useAppToast } from '@/hooks/useAppToast';
import { C_M } from '@/constants/typo/submit-alerts';

interface ElementType extends Omit<FormElement, 'options'> {
  attributes?: UnknownRecord;
  options?: FormOption[];
  element: 'input' | 'select' | 'date';
  type: string;
  props?: {
    onchange?: DropDownOnChange;
  };
}

interface DropdownOption {
  id: string | number;
  label: string;
  [key: string]: string | number;
}

interface DropDownOnChange {
  fn?: any;
  required_fields?: string[];
  parent_element_id: string;
  child_element_id: string;
}

type AddFormProps = {
  bucket: BucketProp['bucket'];
  onSuccess?: () => void;
  setIsOpen: fnBool;
};

// Define a proper form type that includes all possible fields
interface AddFormValues extends FieldValues {
  [key: string]: unknown;
  items?: unknown[];
  actions?: unknown[];
}

const AddForm = ({ bucket, onSuccess, setIsOpen }: AddFormProps) => {
  const { showSuccess, showError } = useAppToast();
  const [dropdownOptionsMap, setDropdownOptionsMap] = useState<
    Record<string, DropdownOption[]>
  >({});
  const [ocDropdownOptionsMap, setOcDropdownOptionsMap] = useState<
    Record<string, { id: string | number; label: string }[]>
  >({});

  const selector = bucket?.crud?.add;

  // ✅ Create a fallback schema for when schemaValidator is undefined
  const schemaValidator = selector?.schema?.validator as
    | z.ZodType<MixRecord>
    | undefined;

  // Create a fallback schema that accepts any object
  const fallbackSchema = z.object({});
  const resolvedSchema = schemaValidator || fallbackSchema;

  const defaultValues = (selector?.schema?.default_values as MixRecord) || {};
  type FormSchemaType = z.infer<typeof resolvedSchema> & AddFormValues;

  // ✅ Now zodResolver always receives a valid ZodType
  const form = useForm<FormSchemaType>({
    resolver: zodResolver(resolvedSchema),
    defaultValues,
  });

  const {
    formState: { isSubmitting },
  } = form;

  // ✅ Wrap elements in useMemo to prevent unnecessary dependency changes
  const elements = useMemo(
    () => selector?.elements || {},
    [selector?.elements],
  );

  const [formData, setFormData] = useState<Record<string, unknown | null>>({});

  const handleChange = (id: string, value: string) => {
    setFormData((prev) => {
      const updated = { ...prev, [id]: value };
      return updated;
    });
  };

  // Submit handler
  const onSubmit = async (data: FormSchemaType) => {
    try {
      const response = (await globalApiPost(
        selector?.endpoint as string,
        data,
        false,
      )) as UnknownRecord;

      if (!response?.success) {
        showError((response as any).errors, C_M.CREATE_FAILED);
      } else {
        showSuccess(C_M.CREATE_SUCCESS);
        onSuccess?.();
        setIsOpen(false);
      }
    } catch (error) {
      console.error('Submission error:', error);
      showError(error, C_M.SUBMIT_ERROR);
    }
  };

  const handleDropDownOnChange = async (
    onchange: DropDownOnChange,
    value: unknown,
  ) => {
    const updatedMap: Record<string, { id: string | number; label: string }[]> =
      {};

    switch (onchange.parent_element_id) {
      case 'institute_enquiry_visa_service_country': {
        const data = await prepareAddEditFormDropdown(
          'institute_enquiry_institute',
          { country_id: value },
        );
        updatedMap[onchange.child_element_id] = transformSelectOptions(data);
        setOcDropdownOptionsMap((prev) => ({ ...prev, ...updatedMap }));
        break;
      }

      case 'institute_enquiry_institute': {
        const data = await prepareAddEditFormDropdown(
          'institute_enquiry_intake',
          {
            institute_id: value,
            client_from_country_id: formData['client_from_country_id'],
            visa_service_country_id: formData['visa_service_country_id'],
          },
        );
        updatedMap[onchange.child_element_id] = transformSelectOptions(data);
        setOcDropdownOptionsMap((prev) => ({ ...prev, ...updatedMap }));
        break;
      }

      case 'institute_enquiry_intake': {
        const data = await prepareAddEditFormDropdown(
          'institute_enquiry_commission_instance',
          {
            intake_id: value,
            institute_id: formData['institute_id'],
            client_from_country_id: formData['client_from_country_id'],
            visa_service_country_id: formData['visa_service_country_id'],
          },
        );
        updatedMap[onchange.child_element_id] = transformSelectOptions(data);
        setOcDropdownOptionsMap((prev) => ({ ...prev, ...updatedMap }));
        break;
      }

      default:
        break;
    }
  };

  // Load all dropdown options in a single batch
  useEffect(() => {
    // Only proceed if selector exists and has elements
    if (!selector || !elements) return;

    const loadAllDropdowns = async () => {
      for (const elKey of Object.keys(elements)) {
        const el = elements[elKey] as unknown as {
          id: string;
          options_id?: string;
          options?: unknown[];
        };

        const args = elements[elKey]?.args ?? {};
        if (el?.options_id) {
          try {
            const data = await prepareAddEditFormDropdown(el.options_id, args);
            if (Array.isArray(data) && data.length > 0) {
              setDropdownOptionsMap((prev) => ({
                ...prev,
                [el.id]: transformSelectOptions(
                  data as MixRecord[],
                ) as DropdownOption[],
              }));
            }
          } catch (err) {
            console.error(`Failed to load dropdown for ${el.id}`, err);
          }
        }
      }
    };

    loadAllDropdowns();
  }, [selector, elements]);

  const getFormElement = (elementRaw: unknown): FormElement | null => {
    if (typeof elementRaw !== 'object' || elementRaw === null) {
      return null;
    }

    const element = elementRaw as Record<string, unknown>;

    // ✅ Type guard to check if it has the required properties
    if (
      typeof element.id === 'string' &&
      typeof element.title === 'string' &&
      (element.element === 'input' || element.element === 'select')
    ) {
      return {
        id: element.id as string,
        title: element.title as string,
        element: element.element as 'input' | 'select',
        options: element.options as
          | { id: string | number; label: string }[]
          | undefined,
        options_id: element.options_id as string | undefined,
        attributes: element.attributes as { required?: boolean } | undefined,
        type: element.type as string,
        props: element.props as { onchange?: DropDownOnChange } | undefined,
      };
    }

    return null;
  };

  // Create a custom onChange handler that wraps the field's onChange
  const createCustomOnChange = (
    field:
      | InputFieldProps
      | SelectFieldProps
      | MultiSelectFieldProps
      | DateFieldProps,
    element: FormElement,
  ) => {
    return (value: unknown) => {
      // Call the original field onChange
      field.onChange(value as never);

      // Handle form data tracking
      handleChange(element.id as string, value as string);

      // Handle dropdown change propagation
      if (
        (element as ElementType).type === 'select' &&
        ((element as ElementType)?.props?.onchange as DropDownOnChange)
      ) {
        handleDropDownOnChange(
          (element as ElementType)?.props?.onchange as DropDownOnChange,
          value,
        );
      }
    };
  };

  // Type-safe field props creator
  const createFieldProps = (
    field:
      | InputFieldProps
      | SelectFieldProps
      | MultiSelectFieldProps
      | DateFieldProps,
    element: FormElement,
  ) => {
    const customOnChange = createCustomOnChange(field, element);

    const baseProps = {
      onChange: customOnChange,
      onBlur: field.onBlur,
      value: field.value,
      name: field.name,
      ref: field.ref,
    };

    // Return properly typed field props based on element type
    switch (element.element) {
      case 'input':
        return {
          ...baseProps,
          value: field.value as string | number | undefined,
          placeholder: element.title,
        } as InputFieldProps;

      case 'select':
        return {
          ...baseProps,
          value: field.value as string | number | undefined,
          placeholder: element.title,
        } as SelectFieldProps;

      case 'date':
        return {
          ...baseProps,
          value: field.value as Date | undefined,
        } as DateFieldProps;

      default:
        return baseProps as InputFieldProps;
    }
  };

  // Type guard to ensure element id is a valid form path
  const isValidFormPath = (id: string): id is Path<FormSchemaType> => {
    return id in (defaultValues || {});
  };

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
        <Text className="main-scroll-widget">
          <Text className="flex flex-wrap p-2 form-mid mt-0">
            {Object.entries(elements).map(([key, elementRaw]) => {
              // ✅ Use the safe casting function
              const element = getFormElement(elementRaw);

              // ✅ Skip rendering if element is invalid
              if (!element) {
                console.warn(
                  `Invalid form element configuration for key: ${key}`,
                );
                return null;
              }

              // Skip if element id is not a valid form path
              if (!isValidFormPath(element.id)) {
                console.warn(
                  `Element id '${element.id}' is not a valid form path for key: ${key}`,
                );
                return null;
              }

              return (
                <FormField
                  key={key}
                  control={form.control}
                  name={element.id as Path<FormSchemaType>}
                  render={({ field }) => (
                    <FormItem className="w-1/4 p-2">
                      <FormLabel className="no-error-styles font-bold">
                        {element.attributes?.required && (
                          <span className="text-red-600 pl-1">*</span>
                        )}
                        {element.title}
                      </FormLabel>
                      <FormControl>
                        <FormFieldRenderer
                          form={form}
                          element={element as ElementType}
                          field={createFieldProps(
                            field as
                              | InputFieldProps
                              | SelectFieldProps
                              | MultiSelectFieldProps
                              | DateFieldProps,
                            element,
                          )}
                          dropdownOptions={
                            ocDropdownOptionsMap[element.id] ||
                            dropdownOptionsMap[element.id] ||
                            []
                          }
                        />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />
              );
            })}
          </Text>

          {bucket.table_id === 'MENUS' && (
            <MenuActionItems
              control={
                form.control as unknown as Control<FormDataWithMenuActions>
              }
              name="actions"
              record={{}}
            />
          )}
        </Text>

        <Text className="modal-footer flex justify-end items-end footer-modal text-right gap-2 m-0 pr-4 p-2">
          <DialogClose asChild>
            <Button
              type="button"
              className="m-0 filter-search-btn tracking-wider w-40 primary-button"
            >
              Cancel
            </Button>
          </DialogClose>
          <Button
            type="submit"
            disabled={isSubmitting}
            className="m-0 filter-search-btn tracking-wider w-40 primary-button flex items-center justify-center gap-2"
          >
            {isSubmitting && (
              <span className="h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" />
            )}
            {isSubmitting ? 'Adding...' : 'Add'}
          </Button>
        </Text>
      </form>
    </Form>
  );
};

export default React.memo(AddForm);
