import React, { useState } from 'react';
import { MdModeEdit } from 'react-icons/md';
import { useLanguage } from '../../../../providers/language/LanguageContext';
import { Popup } from '../../../UiComponents/Popup';
import { FormGeneratorForm, AttributeDefinition } from '../../FormGeneratorForm';
import styles from '../ActionButton.module.css';

export interface EditActionButtonProps<T = any> {
  row: T;
  onEdit?: (row: T) => void;
  disabled?: boolean | { disabled: boolean; message?: string };
  loading?: boolean;
  className?: string;
  title?: string;
  isEditing?: boolean;
  hookData: any; // REQUIRED: Contains all hook data including operations
  // Field mappings
  idField?: string; // Field name for the unique identifier
  nameField?: string; // Field name for display name
  typeField?: string; // Field name for type/mime type
  operationName?: string; // Name of the operation function in hookData
  loadingStateName?: string; // Name of the loading state in hookData
  // Function name in hookData to fetch a single item (e.g., 'fetchPromptById', 'fetchItem')
  fetchItemFunctionName?: string;
  // Entity type for FormGeneratorForm (e.g., "Prompt", "User", "FileItem")
  entityType?: string;
  // Optional: Pre-fetched attributes (if available in hookData)
  attributes?: any[];
}

export function EditActionButton<T = any>({
  row,
  onEdit,
  disabled = false,
  loading = false,
  className = '',
  title,
  isEditing = false,
  hookData,
  idField = 'id',
  operationName = 'handleFileUpdate',
  loadingStateName = 'editingFiles',
  fetchItemFunctionName = 'fetchPromptById',
  entityType,
  attributes: providedAttributes
}: EditActionButtonProps<T>) {
  const { t } = useLanguage();
  const [internalLoading, setInternalLoading] = useState(false);
  const [isPopupOpen, setIsPopupOpen] = useState(false);
  const [editData, setEditData] = useState<T | null>(null);
  const [fetchingData, setFetchingData] = useState(false);
  
  // Extract disabled state and tooltip message
  const isDisabled = typeof disabled === 'boolean' ? disabled : disabled?.disabled || false;
  const disabledMessage = typeof disabled === 'object' ? disabled?.message : undefined;
  

  
  // Validate that hookData is provided
  if (!hookData) {
    throw new Error('EditActionButton requires hookData to be provided');
  }

  // Get entity type from hookData or props
  const getEntityType = (): string | undefined => {
    if (entityType) return entityType;
    if (hookData.entityType) return hookData.entityType;
    if (hookData.entityName) return hookData.entityName;
    // Try to infer from hookData attributes if available
    if (hookData.attributes && Array.isArray(hookData.attributes) && hookData.attributes.length > 0) {
      // Could potentially infer from attribute structure, but safer to require explicit entityType
      return undefined;
    }
    return undefined;
  };

  // Get attributes from hookData or props
  const getAttributes = () => {
    if (providedAttributes) return providedAttributes;
    if (hookData.attributes && Array.isArray(hookData.attributes)) return hookData.attributes;
    return undefined;
  };

  const handleClick = async (e: React.MouseEvent) => {
    e.stopPropagation();
    if (!isDisabled && !loading && !isEditing && !internalLoading && !fetchingData && !isPopupOpen) {
      setInternalLoading(true);
      setFetchingData(true);
      
      try {
        // Call the onEdit callback if provided
        if (onEdit) {
          await onEdit(row);
        }
        
        const itemId = (row as any)[idField];
        
        // Fetch current item data - use generic fetch function from hookData
        let freshData: T | null = null;
        if (itemId) {
          const possibleFunctionNames = [
            fetchItemFunctionName,
            'fetchItemById',
            'fetchItem',
            'getItemById',
            'getItem'
          ].filter(Boolean);
          
          let fetchFunction: ((id: string) => Promise<T | null>) | null = null;
          for (const funcName of possibleFunctionNames) {
            if (hookData[funcName] && typeof hookData[funcName] === 'function') {
              fetchFunction = hookData[funcName];
              break;
            }
          }
          
          if (fetchFunction) {
            try {
              freshData = await fetchFunction(itemId);
            } catch (error: any) {
              console.error('Failed to fetch fresh data:', error);
            }
          }
        }
        
        // Ensure attributes are loaded - use generic function from hookData if available
        if (hookData.ensureAttributesLoaded && typeof hookData.ensureAttributesLoaded === 'function') {
          await hookData.ensureAttributesLoaded();
        }
        
        // Use fresh data if available, otherwise use row data
        setEditData(freshData || row);
        
        // Set fetchingData to false first
        setFetchingData(false);
        
        // Wait for React to update state
        await new Promise(resolve => setTimeout(resolve, 0));
        
        // Open popup AFTER data is ready - like CreateButton (no loading state shown)
        setIsPopupOpen(true);
      } finally {
        setInternalLoading(false);
      }
    }
  };

  const handleSave = async (updatedData: T) => {
    if (!editData) return;

    try {
      setInternalLoading(true);
      
      // Get the item ID from the row
      const itemId = (editData as any)[idField];
      
      // Get edit fields configuration from attributes
      const attributes = getAttributes();
      const fields = attributes || [];
      
      // Extract the fields to update from the edit data
      const updateData: any = {};
      fields.forEach((field: AttributeDefinition) => {
        if (field.editable !== false) {
          const fieldName = field.name;
          const value = (updatedData as any)[fieldName];
          if (value !== undefined) {
            updateData[fieldName] = value;
          }
        }
      });

      // Check if optimistic update is available
      const updateOptimistically = hookData.updateOptimistically;

      // Validate required operation exists
      if (!hookData[operationName]) {
        throw new Error(`EditActionButton requires hookData.${operationName} to be defined`);
      }

      // Optimistically update the UI immediately
      if (updateOptimistically) {
        updateOptimistically(itemId, updateData);
      }

      // Use hookData operation to update in the background
      const result = await hookData[operationName](itemId, updateData, editData);
      const success = result?.success || result === true;

      if (success) {
        // Close popup and reset state on success
        setIsPopupOpen(false);
        setEditData(null);
        
        // If we used optimistic update, refetch to get fresh data from backend
        // This ensures we have the latest data including any server-side transformations
        if (hookData.refetch) {
          await hookData.refetch();
        }
      } else {
        // If update failed, revert optimistic update
        if (updateOptimistically && hookData.refetch) {
          // Revert by refetching original data
          await hookData.refetch();
        }
        
        // Close popup on error
        setIsPopupOpen(false);
        setEditData(null);
      }
    } catch (error: any) {
      // If update failed, revert optimistic update
      if (hookData.updateOptimistically && hookData.refetch) {
        await hookData.refetch();
      }
      
      console.error('Failed to update item:', error);
      setIsPopupOpen(false);
      setEditData(null);
    } finally {
      setInternalLoading(false);
    }
  };

  const handleCancel = () => {
    setIsPopupOpen(false);
    setEditData(null);
  };

  const buttonTitle = title || t('files.action.edit', 'Edit');
  // Use hookData editing state if available, otherwise use passed isEditing
  const loadingState = hookData?.[loadingStateName];
  const actualIsEditing = loadingState?.has((row as any)[idField]) || isEditing;
  const isLoading = loading || actualIsEditing || internalLoading || fetchingData;

  // Determine the final button title (tooltip)
  const finalTitle = isDisabled && disabledMessage ? disabledMessage : buttonTitle;

  return (
    <>
      <button
        onClick={handleClick}
        className={`${styles.actionButton} ${styles.edit} ${isLoading ? styles.loading : ''} ${isDisabled ? styles.disabled : ''} ${className}`}
        title={finalTitle}
        disabled={isDisabled || isLoading}
      >
        <span className={styles.actionIcon}>
          {isLoading ? '⏳' : <MdModeEdit />}
        </span>
      </button>

      {/* Edit Popup - Identical structure to CreateButton */}
      <Popup
        isOpen={isPopupOpen}
        title={t('files.edit.title', 'Edit Item')}
        onClose={handleCancel}
        size="medium"
        closable={!internalLoading}
      >
        {editData && (() => {
          const entityTypeValue = getEntityType();
          const attributesValue = getAttributes();
          
          if (!entityTypeValue && !attributesValue) {
            console.warn('EditActionButton: entityType or attributes must be provided for FormGeneratorForm');
            return (
              <div style={{ padding: '20px', textAlign: 'center' }}>
                {t('common.error', 'Error: Entity type or attributes must be provided')}
              </div>
            );
          }
          
          return (
            <FormGeneratorForm
              entityType={entityTypeValue}
              attributes={attributesValue}
              data={editData}
              mode="edit"
              onSubmit={handleSave}
              onCancel={handleCancel}
              submitButtonText={t('common.save', 'Save')}
              cancelButtonText={t('common.cancel', 'Cancel')}
            />
          );
        })()}
      </Popup>
    </>
  );
}

export default EditActionButton;
