import { useState, useEffect } from 'react';

/**
 * Custom hook to load and manage related entity fields from OpenAPI schema
 */
export const useRelatedEntityFields = (selectedEntity, selectedBundle, includes, baseUrl) => {
  const [relatedEntityFields, setRelatedEntityFields] = useState({});
  const [loadingRelatedFields, setLoadingRelatedFields] = useState(false);

  // Advanced relationship field loading with better state management
  useEffect(() => {
    // Generate a unique request ID for this run to avoid race conditions
    const requestId = Date.now().toString();

    const loadIncludeFields = async () => {
      // Only run if we have a valid entity and bundle and includes
      if (!selectedEntity || !selectedBundle || includes.length === 0) {
        if (includes.length === 0) {
          // Clear related fields when no includes are selected
          setRelatedEntityFields({});
        }
        setLoadingRelatedFields(false);
        return;
      }

      // Indicate loading started
      setLoadingRelatedFields(true);

      try {
        // Get current related fields as a base (always start with a clean slate)
        let newRelatedFields = {};

        // Track completed includes for progress
        let completedIncludes = 0;
        const totalIncludes = includes.length;

        // Fetch the OpenAPI schema once for efficiency
        const openApiUrl = baseUrl.replace(/\/jsonapi\/?$/, '/openapi/jsonapi');

        const openApiResponse = await fetch(openApiUrl);
        if (!openApiResponse.ok) {
          throw new Error(`OpenAPI schema request failed with status ${openApiResponse.status}`);
        }

        const openApiData = await openApiResponse.json();

        // Create an array of promises for parallel processing
        const processPromises = includes.map(async (include) => {
          try {
            // Get the current entity schema from OpenAPI
            const currentEntityType = `${selectedEntity}--${selectedBundle}`;
            const currentEntitySchema = openApiData.definitions?.[currentEntityType];

            if (!currentEntitySchema) {
              return { include, fields: [] };
            }

            // Find the relationship in the entity schema
            const relationshipsSchema = currentEntitySchema.properties?.data?.properties?.relationships?.properties;
            if (!relationshipsSchema || !relationshipsSchema[include]) {
              return { include, fields: [] };
            }

            const includeDef = relationshipsSchema[include];

            // Extract target type from relationship definition
            let targetType = null;
            let targetBundle = null;
            let targetFullType = null;

            // Check data property for to-one relationship
            if (includeDef.properties?.data?.properties?.type?.enum?.[0]) {
              targetFullType = includeDef.properties.data.properties.type.enum[0];
              [targetType, targetBundle] = targetFullType.split('--');
            }
            // Check items for to-many relationship
            else if (includeDef.properties?.data?.items?.properties?.type?.enum?.[0]) {
              targetFullType = includeDef.properties.data.items.properties.type.enum[0];
              [targetType, targetBundle] = targetFullType.split('--');
            }

            if (!targetType || !targetBundle) {
              return { include, fields: [] };
            }

            // Get target entity schema from the same OpenAPI schema
            const targetEntityType = `${targetType}--${targetBundle}`;
            const targetSchema = openApiData.definitions?.[targetEntityType];

            if (!targetSchema) {
              return { include, fields: [] };
            }

            // Extract fields from target schema
            const targetFields = [];

            // Store info about this relationship for associating with direct fields later
            const includeInfo = {
              targetEntityType: targetEntityType,
              title: includeDef.title || include,
              description: includeDef.description || `The ${include} include`
            };

            // Add the relationship field to ensure it's available
            targetFields.push({
              name: include,
              // Create basic metadata for the base relationship
              fieldDef: {
                title: includeDef.title || `${include} (Include)`,
                description: includeDef.description || `The ${include} include`,
                type: 'include'
              },
              // Store this as a base include field
              isBaseInclude: true,
              // Store target entity type
              targetEntityType: targetEntityType,
              // Store include info
              includeInfo: includeInfo
            });

            // In OpenAPI 2.0, fields are in data.attributes.properties
            const attributesSchema = targetSchema.properties?.data?.properties?.attributes?.properties;
            if (attributesSchema) {
              // Process attributes from target entity
              Object.keys(attributesSchema).forEach(fieldName => {
                // Create the prefixed field name (e.g., uid.name)
                const prefixedFieldName = `${include}.${fieldName}`;
                targetFields.push({
                  name: prefixedFieldName,
                  // Include metadata from original field
                  fieldDef: attributesSchema[fieldName],
                  // Store include target entity type for later use in field params
                  targetEntityType: targetEntityType,
                  // Store the base include name for UI logic
                  baseInclude: include
                });
              });
            }

            // Return the fields for this relationship
            return { include, fields: targetFields };
          } catch (error) {
            return { include, fields: [] };
          }
        });

        // Wait for all relationships to be processed in parallel
        const results = await Promise.all(processPromises);

        // Process results and build the new state
        results.forEach(result => {
          if (result && result.include && result.fields.length > 0) {
            newRelatedFields[result.include] = result.fields;
          }
        });

        // Set state in a way that ensures we don't miss updates
        setRelatedEntityFields(prevFields => {
          // Merge with any existing fields for relationships that weren't in this batch
          const mergedFields = { ...prevFields };

          // Add the newly loaded fields
          Object.keys(newRelatedFields).forEach(rel => {
            mergedFields[rel] = newRelatedFields[rel];
          });

          return mergedFields;
        });
      } catch (error) {
        // Handle errors silently - failures will just result in no fields being shown
      } finally {
        // Clear the loading state after a short delay to ensure rendering completes
        setTimeout(() => {
          setLoadingRelatedFields(false);
        }, 300);
      }
    };

    // Execute the function
    loadIncludeFields();

    // Cleanup function
    return () => {};
  }, [selectedEntity, selectedBundle, includes, baseUrl]);

  return { relatedEntityFields, loadingRelatedFields, setRelatedEntityFields };
};
