import React, { useState, useEffect } from 'react';
import GroupedFieldSelect from './GroupedFieldSelect';

function SortSelector({ selectedEntity, selectedBundle, sorts, onSortsChange, relatedEntityFields, baseUrl }) {
  const [newSort, setNewSort] = useState({ field: '', direction: 'asc' });
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [directFields, setDirectFields] = useState([]);

  useEffect(() => {
    if (selectedEntity && selectedBundle) {
      fetchFields();
    } else {
      setDirectFields([]);
    }
  }, [selectedEntity, selectedBundle]);

  // Determines whether a resourceType is a content entity type. We can identify
  // them heuristically because content entity types use the format
  // "entity_type--bundle".
  const isContentEntityType = (resourceType) => resourceType.includes('--');

  // Handles schema errors by setting error state and clearing fields.
  const handleSchemaError = (msg) => {
    setError(msg);
    setDirectFields([]);
    setAvailableFields([]);
    setLoading(false);
  };

  const fetchFields = async () => {
    if (!selectedEntity || !selectedBundle) return;

    setLoading(true);
    setError(null);

    try {
      // Use the OpenAPI endpoint instead of resource/schema
      const openApiUrl = drupalSettings.path.baseUrl + "openapi/jsonapi"

      const response = await fetch(openApiUrl);

      if (response.ok) {
        const data = await response.json();

        // Extract fields from the schema
        let fieldNames = [];
        const PRIMITIVE_TYPES = ["string", "integer", "boolean", "number"];
        const resourceType = `${selectedEntity}--${selectedBundle}`;
        let attributes = null;

        const resourceSchema = data.definitions?.[resourceType];
        // If the resource is a content entity type and the schema exists but is
        // malformed, throw an error.
        if (resourceSchema && isContentEntityType(resourceType)) {
          if (!resourceSchema.properties?.data?.properties?.attributes?.properties) {
            handleSchemaError(`No attributes found in OpenAPI schema for resource type: ${resourceType}`);
            return;
          }
          attributes = resourceSchema.properties.data.properties.attributes.properties;
        } else if (resourceSchema) {
          // Config entities with a schema: use attributes if present.
          attributes = resourceSchema.properties?.data?.properties?.attributes?.properties;
        } else {
          // No schema: just provide 'id', no error.
          attributes = undefined;
        }

        if (attributes) {
          Object.entries(attributes).forEach(([field, def]) => {
            if (PRIMITIVE_TYPES.includes(def.type)) {
              fieldNames.push(field);
            }
          });
        }

        // Ensure 'id' is present, because it's always available for sorting but
        // doesn't always show up in the schema.
        if (!fieldNames.includes('id')) {
          fieldNames.push('id');
        }

        // Always include 'langcode' for content entity types, which always
        // exist but don't always show up in the schema.
        if (isContentEntityType(resourceType) && !fieldNames.includes('langcode')) {
          fieldNames.push('langcode');
        }

        // Store direct fields separately
        setDirectFields(fieldNames);
      } else {
        setError(`Schema endpoint failed with status: ${response.status}`);

        // Fallback to the mock fields if the schema endpoint fails
        const mockFields = getMockFields(selectedEntity);
        setDirectFields(mockFields);
      }
    } catch (err) {
      // Handle error and set fallback fields
      setError(`Unable to get fields: ${err.message}`);

      // Fallback to the mock fields if there's an error
      const mockFields = getMockFields(selectedEntity);
      setDirectFields(mockFields);
    } finally {
      setLoading(false);
    }
  };

  const getMockFields = (entityType) => {
    switch(entityType) {
      case 'node':
        return ['id', 'title', 'created', 'changed', 'status'];
      case 'user':
        return ['id', 'name', 'created', 'access', 'status'];
      case 'taxonomy_term':
        return ['id', 'name', 'weight'];
      default:
        return ['id', 'created', 'changed'];
    }
  };

  const handleAddSort = () => {
    if (newSort.field) {
      onSortsChange([...sorts, { ...newSort }]);
      setNewSort({ field: '', direction: 'asc' });
    }
  };

  const handleRemoveSort = (index) => {
    const updatedSorts = [...sorts];
    updatedSorts.splice(index, 1);
    onSortsChange(updatedSorts);
  };

  const handleToggleSortDirection = (index) => {
    const updatedSorts = [...sorts];
    updatedSorts[index].direction = updatedSorts[index].direction === 'asc' ? 'desc' : 'asc';
    onSortsChange(updatedSorts);
  };

  const handleClearAll = () => {
    onSortsChange([]);
  };

  return (
    <div className="sort-selector form-item">
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
        <h4 className="form-item__label" style={{ margin: 0 }}>Sort</h4>
        <button
          className="button button--small"
          onClick={handleClearAll}
          disabled={sorts.length === 0}
        >
          Clear
        </button>
      </div>

      {(selectedEntity && selectedBundle) ? (
        <>
          <div className="claro-details">
            <div className="claro-details__wrapper">
              {loading ? (
                <div className="form-item__description">
                  <div className="spinner" style={{ display: 'inline-block', marginRight: '8px' }}></div>
                  Loading fields for sorting…
                </div>
              ) : error ? (
                <div className="messages messages--error">
                  {error}
                </div>
              ) : (
                <>
                  {sorts.length > 0 ? (
                    <>
                      <h5 className="sort-group-title">Selected sort criteria</h5>
                      <div className="fields-chips">
                        {sorts.sort().map((sort, index) => (
                          <span
                            key={index}
                            className={`gin-chip gin-chip--primary ${sort.field.includes('.') ? 'gin-chip--relationship' : ''}`}
                          >
                            {sort.field}
                            <span
                              className="sort-direction-toggle"
                              onClick={() => handleToggleSortDirection(index)}
                              style={{ cursor: 'pointer', margin: '0 4px' }}
                              data-testid="toggle-sort-button"
                            >
                              {sort.direction === 'asc' ? '↑' : '↓'}
                            </span>
                            <button
                              className="gin-chip--remove"
                              onClick={() => handleRemoveSort(index)}
                              aria-label={`Remove ${sort.field} sort`}
                            >
                              ✕
                            </button>
                          </span>
                        ))}
                      </div>
                    </>
                  ) : (
                    <div className="form-item__description">
                      No sort criteria applied yet
                    </div>
                  )}

                  <h5 className="sort-group-title" style={{ marginTop: '16px' }}>Add sort criteria</h5>
                  <div className="sort-selector__inputs-row" style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
                    <div className="form-item" style={{ flex: '1 1 200px', minWidth: '150px', marginBottom: '8px' }}>
                      <label className="form-item__label" htmlFor="sort-field">Field</label>
                      <GroupedFieldSelect
                        id="sort-field"
                        value={newSort.field}
                        onChange={(val) => setNewSort({ ...newSort, field: val })}
                        directFields={directFields}
                        relatedEntityFields={relatedEntityFields}
                        usedFields={sorts.map(s => s.field)}
                      />
                    </div>

                    <div className="form-item" style={{ flex: '1 1 200px', minWidth: '150px', marginBottom: '8px' }}>
                      <label className="form-item__label" htmlFor="sort-direction">Direction</label>
                      <select
                        id="sort-direction"
                        className="form-element"
                        value={newSort.direction}
                        onChange={(e) => setNewSort({ ...newSort, direction: e.target.value })}
                      >
                        <option value="asc">Ascending</option>
                        <option value="desc">Descending</option>
                      </select>
                    </div>
                  </div>

                  <div style={{ marginTop: '8px', marginBottom: '16px' }}>
                    <button
                      id="sort-add-button"
                      className="button button--small"
                      onClick={handleAddSort}
                      disabled={!newSort.field}
                      data-testid="add-sort-button"
                    >
                      Add
                    </button>
                  </div>

                  {relatedEntityFields && Object.keys(relatedEntityFields).length > 0 && (
                    <div className="form-item__description" style={{ marginTop: '8px', color: '#6b84a3' }}>
                      <strong>Note:</strong> Include fields (shown in blue) are available because you have added includes to your query.
                    </div>
                  )}
                </>
              )}
            </div>
          </div>
        </>
      ) : (
        <div className="form-item__description">
          Select an entity type and **bundle** to add sort criteria
        </div>
      )}
    </div>
  );
}

export default SortSelector;
