import React, { useMemo, useEffect, Fragment, useState } from 'react';
import { View, Linking, Alert } from 'react-native';
import * as Yup from 'yup';
import type { ContentItem, FormProperty } from '../types';
import { FormRenderer } from './FormRenderer';
import { Formik } from 'formik';
import { getLayoutStyles, getViewStyles } from '../utils/styleKeys';
import { ScrollView } from 'react-native';
import { RenderBasicElement } from '../ContentItem/renderers';
import type { ContentViewItem } from '../store/contentModel';
import { getChildren } from '../utils';
import Resync from 'resync-javascript';

interface ContentFormRendererProps {
  form: ContentItem;
  contentItem: ContentViewItem;
}

export const ContentFormRenderer: React.FC<ContentFormRendererProps> = ({
  form,
  contentItem,
}) => {
  const formData = form.data as FormProperty;
  const [isSubmitted, setIsSubmitted] = useState(false);

  useEffect(() => {
    if (form?.event && contentItem?.content?.id) {
      if (form.eventConfig?.action === 'view') {
        Resync.logEvent({
          eventId: form.event?.eventId || '',
          logId: form.eventConfig?.logId || '',
        });
        if (contentItem?.logAnalytics && form.eventConfig?.logId) {
          contentItem.logAnalytics(form.eventConfig?.logId, {
            itemId: form?.itemId,
            contentViewId: contentItem?.content?.id,
            ...form.eventConfig,
          });
        }
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Helper function to render form content items (sections or form elements)
  const renderFormContentItem = (
    element: ContentItem,
    formValues: Record<string, any>,
    formHandlers: {
      handleChange: (field: string) => (value: any) => void;
      handleBlur: (field: string) => () => void;
      handleSubmit: () => void;
      setFieldTouched: (field: string) => void;
    },
    formState: {
      errors: Record<string, any>;
      touched: Record<string, any>;
      isSubmitting: boolean;
    }
  ) => {
    if (element.type === 'section') {
      // Lazy load RenderSection to avoid circular dependency
      const { RenderSection } = require('../ContentItem/section');
      return (
        <RenderSection
          section={element}
          formValues={formValues}
          formHandlers={formHandlers}
          formState={formState}
          contentItem={contentItem}
        />
      );
    } else {
      if (
        ['text', 'image', 'button', 'divider', 'icon'].includes(
          element.elementType as string
        )
      ) {
        return (
          <RenderBasicElement
            element={element}
            dataItem={undefined}
            contentItem={contentItem}
          />
        );
      }
      // Render form element
      return (
        <FormRenderer
          key={element.itemId}
          element={element as any}
          value={formValues?.[element?.name]}
          onChange={formHandlers?.handleChange(element.name)}
          onBlur={() => formHandlers.setFieldTouched(element.name)}
          onSubmit={formHandlers.handleSubmit}
          error={formState?.errors?.[element.name] as string}
          touched={formState?.touched?.[element.name] as boolean | undefined}
          disabled={formState.isSubmitting}
          loading={formState.isSubmitting}
          contentItem={contentItem}
        />
      );
    }
  };

  // Get child elements of this form
  const formElements = getChildren(form.itemId, contentItem?.content);

  // Helper function to recursively collect all form elements (including those in sections)
  const getAllFormElements = (items: ContentItem[]): ContentItem[] => {
    const allElements: ContentItem[] = [];

    items.forEach((item) => {
      if (item.type === 'section') {
        // Get children of section and recursively process them
        const sectionChildren = getChildren(item.itemId, contentItem?.content);
        allElements.push(...getAllFormElements(sectionChildren));
      } else if (
        ['input', 'select', 'checkbox', 'radio', 'textarea'].includes(
          item.elementType as string
        )
      ) {
        // This is a form element
        allElements.push(item);
      }
    });

    return allElements;
  };

  // Get all form elements including those nested in sections
  const allFormElements = getAllFormElements(formElements);

  const handleSubmitSuccess = () => {
    // Mark as submitted to hide form immediately if hideAfterSubmission is enabled
    setIsSubmitted(true);

    const { navigationRegistry } = contentItem;

    if (formData.submittedSuccessAction) {
      if (
        formData.submittedSuccessAction?.type === 'in_app_navigate' &&
        formData.submittedSuccessAction?.inAppNavigate?.routeName
      ) {
        switch (formData.submittedSuccessAction?.inAppNavigate?.type) {
          case 'navigate':
            navigationRegistry?.navigate(
              formData.submittedSuccessAction?.inAppNavigate?.routeName!,
              formData.submittedSuccessAction?.inAppNavigate?.params
            );
            break;
          case 'push':
            navigationRegistry?.push(
              formData.submittedSuccessAction?.inAppNavigate?.routeName!,
              formData.submittedSuccessAction?.inAppNavigate?.params
            );
            break;
          case 'goBack':
            navigationRegistry?.goBack();
            break;
          default:
            console.warn(
              'Unknown navigation type:',
              formData.submittedSuccessAction?.inAppNavigate?.type
            );
        }
      } else if (formData.submittedSuccessAction?.type === 'out_app_navigate') {
        Linking.canOpenURL(
          formData.submittedSuccessAction?.outAppNavigate?.url!
        ).then((supported) => {
          if (supported) {
            Linking.openURL(
              formData.submittedSuccessAction?.outAppNavigate?.url!
            );
          }
        });
      } else if (
        formData.submittedSuccessAction?.type === 'alert' &&
        formData.submittedSuccessAction?.alertTitle &&
        formData.submittedSuccessAction?.alertMessage
      ) {
        Alert.alert(
          formData.submittedSuccessAction.alertTitle,
          formData.submittedSuccessAction.alertMessage
        );
      }
    }
  };

  const handleSubmitError = () => {
    const { navigationRegistry } = contentItem;
    if (formData.submittedErrorAction) {
      if (formData.submittedErrorAction?.type === 'in_app_navigate') {
        switch (formData.submittedErrorAction?.inAppNavigate?.type) {
          case 'navigate':
            navigationRegistry?.navigate(
              formData.submittedErrorAction?.inAppNavigate?.routeName!,
              formData.submittedErrorAction?.inAppNavigate?.params
            );
            break;
          case 'push':
            navigationRegistry?.push(
              formData.submittedErrorAction?.inAppNavigate?.routeName!,
              formData.submittedErrorAction?.inAppNavigate?.params
            );
            break;
          case 'goBack':
            navigationRegistry?.goBack();
            break;
          default:
            console.warn(
              'Unknown navigation type:',
              formData.submittedErrorAction?.inAppNavigate?.type
            );
        }
      } else if (formData.submittedErrorAction?.type === 'out_app_navigate') {
        Linking.canOpenURL(
          formData.submittedErrorAction?.outAppNavigate?.url!
        ).then((supported) => {
          if (supported) {
            Linking.openURL(
              formData.submittedErrorAction?.outAppNavigate?.url!
            );
          }
        });
      } else if (formData.submittedErrorAction?.type === 'alert') {
        Alert.alert(
          formData.submittedErrorAction?.alertTitle!,
          formData.submittedErrorAction?.alertMessage!
        );
      }
    }
  };

  const onSubmit = async (values: Record<string, any>) => {
    if (contentItem?.logAnalytics && form.eventConfig?.action === 'submit') {
      contentItem.logAnalytics(form.eventConfig?.logId || '', {
        itemId: form?.itemId,
        ...form.eventConfig,
        metadata: values,
      });
    }
    const { functionRegistry } = contentItem;
    if (!contentItem?.content?.id) {
      console.warn('Content item ID not found');
      return;
    }
    if (formData.submissionType === 'function') {
      const funcName = formData.submissionSettings?.functionName;
      if (funcName && functionRegistry?.[funcName]) {
        await (functionRegistry[funcName](values) as unknown as Promise<void>);
      } else {
        console.warn(`Function "${funcName}" not found in function registry`);
      }
    } else if (formData.submissionType === 'webhook') {
      const webhookUrl = formData.submitUrl;
      if (webhookUrl) {
        try {
          const response = await fetch(webhookUrl, {
            method: 'POST',
            body: JSON.stringify(values),
            headers: formData.submissionSettings?.webhookHeaders,
          });
          if (response.ok) {
            handleSubmitSuccess();
          } else {
            handleSubmitError();
          }
        } catch (error) {
          handleSubmitError();
        }
      } else {
        console.warn('Webhook URL not found');
      }
    } else if (formData.submissionType === 'internal') {
      const response = await Resync.submitForm({
        contentViewId: contentItem?.content?.id,
        data: values,
      });
      if (response) {
        handleSubmitSuccess();
      } else {
        handleSubmitError();
      }
    }
  };

  // Sort form elements by order
  const sortedElements = (formElements || [])?.sort(
    (a, b) => a.order - b.order
  );

  const elementWithValidationRules = (allFormElements || [])?.filter(
    (element) => {
      const elementData = element.data as FormProperty;
      return (
        elementData?.required ||
        elementData?.minLength ||
        elementData?.maxLength ||
        elementData?.min !== undefined ||
        elementData?.max !== undefined ||
        elementData?.pattern ||
        (elementData?.validationRules && elementData.validationRules.length > 0)
      );
    }
  );

  const initialValues = useMemo(() => {
    return allFormElements
      .filter((element) =>
        ['input', 'select', 'checkbox', 'radio', 'textarea'].includes(
          element.elementType as string
        )
      )
      .reduce(
        (acc, element) => {
          const elementData = element.data as FormProperty;

          // Set appropriate default values based on element type
          if (
            element.elementType === 'checkbox' ||
            element.elementType === 'radio'
          ) {
            acc[element.name] = elementData?.defaultValue || false;
          } else if (element.elementType === 'select') {
            acc[element.name] = elementData?.defaultValue || '';
          } else {
            acc[element.name] = elementData?.defaultValue || '';
          }
          return acc;
        },
        {} as Record<string, any>
      );
  }, [allFormElements]);

  const validationSchema = useMemo(() => {
    return elementWithValidationRules.reduce(
      (acc, element) => {
        const elementData = element.data as FormProperty;

        if (!element.name) return acc;

        // Determine base schema type based on input mode
        let schema: any;
        const isNumeric =
          elementData?.inputMode === 'numeric' ||
          elementData?.inputMode === 'decimal';

        if (isNumeric) {
          schema = Yup.number();
        } else {
          schema = Yup.string();
        }

        // Apply required validation
        if (elementData?.required) {
          schema = schema.required('This field is required');
        }

        // Apply legacy validations (for backward compatibility)
        if (!isNumeric) {
          if (elementData?.minLength) {
            schema = schema.min(
              elementData.minLength,
              `Minimum length is ${elementData.minLength}`
            );
          }
          if (elementData?.maxLength) {
            schema = schema.max(
              elementData.maxLength,
              `Maximum length is ${elementData.maxLength}`
            );
          }
          if (elementData?.pattern) {
            schema = schema.matches(
              new RegExp(elementData.pattern),
              `Must match pattern ${elementData.pattern}`
            );
          }
        } else {
          if (elementData?.min !== undefined) {
            schema = schema.min(
              elementData.min,
              `Must be greater than or equal to ${elementData.min}`
            );
          }
          if (elementData?.max !== undefined) {
            schema = schema.max(
              elementData.max,
              `Must be less than or equal to ${elementData.max}`
            );
          }
        }

        // Apply validation rules from array
        // Normalize validationRules to always be an array (handle undefined, {}, null, etc.)
        const validationRules = Array.isArray(elementData?.validationRules)
          ? elementData.validationRules
          : [];

        if (validationRules.length > 0) {
          validationRules.forEach((rule: any) => {
            const errorMessage =
              rule.message || `Validation failed for ${rule.type}`;

            switch (rule.type) {
              case 'email':
                schema = schema.email(errorMessage);
                break;

              case 'url':
                schema = schema.url(errorMessage);
                break;

              case 'minLength':
                if (rule.value) {
                  const minVal = parseInt(rule.value, 10);
                  schema = schema.min(minVal, errorMessage);
                } else {
                  console.warn(`[${element.name}] minLength rule has no value`);
                }
                break;

              case 'maxLength':
                if (rule.value) {
                  const maxVal = parseInt(rule.value, 10);
                  schema = schema.max(maxVal, errorMessage);
                } else {
                  console.warn(`[${element.name}] maxLength rule has no value`);
                }
                break;

              case 'length':
                if (rule.value) {
                  const len = parseInt(rule.value, 10);
                  schema = schema.min(len, errorMessage).max(len, errorMessage);
                }
                break;

              case 'min':
                if (rule.value !== undefined) {
                  schema = schema.min(parseFloat(rule.value), errorMessage);
                }
                break;

              case 'max':
                if (rule.value !== undefined) {
                  schema = schema.max(parseFloat(rule.value), errorMessage);
                }
                break;

              case 'greaterThan':
                if (rule.value !== undefined) {
                  schema = schema.moreThan(
                    parseFloat(rule.value),
                    errorMessage
                  );
                }
                break;

              case 'lessThan':
                if (rule.value !== undefined) {
                  schema = schema.lessThan(
                    parseFloat(rule.value),
                    errorMessage
                  );
                }
                break;

              case 'positive':
                schema = schema.positive(errorMessage);
                break;

              case 'negative':
                schema = schema.negative(errorMessage);
                break;

              case 'pattern':
                if (rule.value) {
                  try {
                    schema = schema.matches(
                      new RegExp(rule.value),
                      errorMessage
                    );
                  } catch (e) {
                    console.warn(
                      `Invalid regex pattern for ${element.name}:`,
                      rule.value
                    );
                  }
                }
                break;

              default:
                console.warn(`Unknown validation rule type: ${rule.type}`);
            }
          });
        }

        acc[element.name] = schema;
        return acc;
      },
      {} as Record<string, Yup.AnySchema>
    );
  }, [elementWithValidationRules]);

  // Hide form immediately after successful submission if hideAfterSubmission is enabled
  if (formData?.hideAfterSubmission && isSubmitted) {
    return null;
  }

  return (
    <Formik
      key={form.itemId}
      initialValues={initialValues}
      onSubmit={onSubmit}
      enableReinitialize
      // validateOnMount
      validationSchema={Yup.object().shape({
        ...validationSchema,
      })}
    >
      {({
        handleSubmit,
        handleChange,
        handleBlur,
        setFieldTouched,
        values,
        errors,
        touched,
        isSubmitting,
      }) => {
        return true ? (
          <ScrollView
            // showsHorizontalScrollIndicator={false}
            // showsVerticalScrollIndicator={false}
            nestedScrollEnabled={true}
            contentContainerStyle={[
              getLayoutStyles(formData.styles),
              getLayoutStyles(formData?.customStyles || {}),
              getViewStyles(formData.styles),
              getViewStyles(formData?.customStyles || {}),
            ]}
          >
            {sortedElements?.map((element) => {
              return (
                <Fragment key={element.itemId}>
                  {renderFormContentItem(
                    element,
                    values,
                    {
                      handleChange: (field: string) => (value: any) =>
                        handleChange(field)(value),
                      handleBlur: (field: string) => () => handleBlur(field),
                      handleSubmit,
                      setFieldTouched,
                    },
                    {
                      errors,
                      touched,
                      isSubmitting,
                    }
                  )}
                </Fragment>
              );
            })}
          </ScrollView>
        ) : (
          <View
            style={[
              getLayoutStyles(formData.styles),
              getLayoutStyles(formData?.customStyles || {}),
              getViewStyles(formData.styles),
              getViewStyles(formData?.customStyles || {}),
              {
                // flexWrap: 'nowrap',
                // flex: 1,
                // alignItems: undefined,
                // justifyContent: undefined,
                // gap: 0,
              },
            ]}
          >
            {sortedElements.map((element) =>
              renderFormContentItem(
                element,
                values,
                {
                  handleChange: (field: string) => (value: any) =>
                    handleChange(field)(value),
                  handleBlur: (field: string) => () => handleBlur(field),
                  handleSubmit,
                  setFieldTouched,
                },
                {
                  errors,
                  touched,
                  isSubmitting,
                }
              )
            )}
          </View>
        );
      }}
    </Formik>
  );
};
