import { useState, useEffect, useCallback } from 'react';
import { useApiRequest } from './useApi';
import { 
  deleteWorkflowApi, 
  deleteWorkflowsApi,
  updateWorkflowApi,
  fetchWorkflows as fetchWorkflowsApi,
  fetchWorkflow as fetchWorkflowByIdApi,
  fetchAttributes as fetchAttributesApi,
  startWorkflowApi,
  stopWorkflowApi,
  deleteMessageApi,
  deleteFileFromMessageApi,
  type Workflow,
  type AttributeDefinition,
  type StartWorkflowRequest
} from '../api/workflowApi';
import { useWorkflowSelection } from '../contexts/WorkflowSelectionContext';
import { usePermissions, type UserPermissions } from './usePermissions';

// Workflow interface matching backend
export interface UserWorkflow {
  id: string;
  mandateId: string;
  status: string;
  name?: string;
  workflowMode?: string;
  [key: string]: any; // Allow additional properties
}

// Re-export AttributeDefinition from workflowApi
export type { AttributeDefinition } from '../api/workflowApi';

// Attribute option interface (from backend)
export interface AttributeOption {
  value: string | number;
  label: string | { [key: string]: string }; // Can be string or object with language keys
}

// Pagination parameters
export interface PaginationParams {
  page?: number;
  pageSize?: number;
  sort?: Array<{ field: string; direction: 'asc' | 'desc' }>;
  filters?: Record<string, any>;
  search?: string;
}

// Workflows list hook
export function useUserWorkflows() {
  const [workflows, setWorkflows] = useState<UserWorkflow[]>([]);
  const [attributes, setAttributes] = useState<AttributeDefinition[]>([]);
  const [permissions, setPermissions] = useState<UserPermissions | null>(null);
  const [pagination, setPagination] = useState<{
    currentPage: number;
    pageSize: number;
    totalItems: number;
    totalPages: number;
  } | null>(null);
  const { request, isLoading: loading, error } = useApiRequest<null, Workflow[]>();
  const { checkPermission } = usePermissions();

  // Fetch attributes from backend
  const fetchAttributes = useCallback(async () => {
    try {
      const attrs = await fetchAttributesApi(request, 'ChatWorkflow');
      setAttributes(attrs);
      return attrs;
    } catch (error: any) {
      console.error('Error fetching attributes:', error);
      setAttributes([]);
      return [];
    }
  }, [request]);

  // Fetch permissions from backend
  const fetchPermissions = useCallback(async () => {
    try {
      const perms = await checkPermission('DATA', 'ChatWorkflow');
      setPermissions(perms);
      return perms;
    } catch (error: any) {
      console.error('Error fetching permissions:', error);
      const defaultPerms: UserPermissions = {
        view: false,
        read: 'n',
        create: 'n',
        update: 'n',
        delete: 'n',
      };
      setPermissions(defaultPerms);
      return defaultPerms;
    }
  }, [checkPermission]);

  const fetchWorkflowsData = useCallback(async (params?: PaginationParams) => {
    try {
      const requestParams: any = {};
      
      // Build pagination object if provided
      if (params) {
        const paginationObj: any = {};
        
        if (params.page !== undefined) paginationObj.page = params.page;
        if (params.pageSize !== undefined) paginationObj.pageSize = params.pageSize;
        if (params.sort) paginationObj.sort = params.sort;
        if (params.filters) paginationObj.filters = params.filters;
        if (params.search) paginationObj.search = params.search;
        
        if (Object.keys(paginationObj).length > 0) {
          requestParams.pagination = JSON.stringify(paginationObj);
        }
      }
      
      let data: any;
      if (Object.keys(requestParams).length > 0) {
        // Use request for paginated queries
        data = await request({
          url: '/api/workflows/',
          method: 'get',
          params: requestParams
        });
      } else {
        // Use API function for simple queries
        data = await fetchWorkflowsApi(request);
      }
      
      // Handle paginated response
      if (data && typeof data === 'object' && 'items' in data) {
        const items = Array.isArray(data.items) ? data.items : [];
        // Map API response to our frontend model
        const mappedWorkflows = items.map((apiWorkflow: any): UserWorkflow => {
          return {
            id: apiWorkflow.id,
            mandateId: apiWorkflow.mandateId || '',
            status: apiWorkflow.status || 'unknown',
            name: apiWorkflow.name,
            workflowMode: apiWorkflow.workflowMode,
            ...apiWorkflow // Include any additional properties
          };
        });
        setWorkflows(mappedWorkflows);
        if (data.pagination) {
          setPagination(data.pagination);
        }
      } else {
        // Handle non-paginated response (backward compatibility)
        const items = Array.isArray(data) ? data : [];
        const mappedWorkflows = items.map((apiWorkflow: any): UserWorkflow => {
          return {
            id: apiWorkflow.id,
            mandateId: apiWorkflow.mandateId || '',
            status: apiWorkflow.status || 'unknown',
            name: apiWorkflow.name,
            workflowMode: apiWorkflow.workflowMode,
            ...apiWorkflow
          };
        });
        setWorkflows(mappedWorkflows);
        setPagination(null);
      }
    } catch (error: any) {
      // Error is already handled by useApiRequest
      setWorkflows([]);
      setPagination(null);
    }
  }, [request]);

  // Optimistically remove a workflow from the local state
  const removeOptimistically = (workflowId: string) => {
    setWorkflows(prevWorkflows => prevWorkflows.filter(workflow => workflow.id !== workflowId));
  };

  // Optimistically update a workflow in the local state
  const updateOptimistically = (workflowId: string, updateData: Partial<UserWorkflow>) => {
    setWorkflows(prevWorkflows => 
      prevWorkflows.map(workflow => 
        workflow.id === workflowId 
          ? { ...workflow, ...updateData }
          : workflow
      )
    );
  };

  // Fetch a single workflow by ID
  const fetchWorkflowById = useCallback(async (workflowId: string): Promise<UserWorkflow | null> => {
    try {
      const workflow = await fetchWorkflowByIdApi(request, workflowId);
      return workflow as UserWorkflow | null;
    } catch (error: any) {
      console.error('Error fetching workflow by ID:', error);
      return null;
    }
  }, [request]);

  // Generate edit fields from attributes dynamically
  const generateEditFieldsFromAttributes = useCallback((): Array<{
    key: string;
    label: string;
    type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'multiselect' | 'readonly';
    editable?: boolean;
    required?: boolean;
    validator?: (value: any) => string | null;
    minRows?: number;
    maxRows?: number;
    options?: Array<{ value: string | number; label: string }>;
    optionsReference?: string; // For options that need to be fetched (e.g., "user.role")
  }> => {
    if (!attributes || attributes.length === 0) {
      return [];
    }

    const editableFields = attributes
      .filter(attr => {
        // Filter out non-editable fields based on readonly/editable flags
        if (attr.readonly === true || attr.editable === false) {
          return false; // Don't show readonly fields in edit form
        }
        // Also filter out common non-editable fields
        const nonEditableFields = ['id', 'mandateId', '_createdBy', '_hideDelete'];
        return !nonEditableFields.includes(attr.name);
      })
      .map(attr => {
        // Map backend attribute type to form field type
        let fieldType: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'multiselect' | 'readonly' = 'string';
        let options: Array<{ value: string | number; label: string }> | undefined = undefined;
        let optionsReference: string | undefined = undefined;
        
        // Map backend types to form field types
        if (attr.type === 'checkbox') {
          fieldType = 'boolean';
        } else if (attr.type === 'email') {
          fieldType = 'email';
        } else if (attr.type === 'date') {
          fieldType = 'date';
        } else if (attr.type === 'select') {
          fieldType = 'enum';
          // Handle options - can be array or string reference
          if (Array.isArray(attr.options)) {
            options = attr.options.map(opt => {
              const labelValue = typeof opt.label === 'string' 
                ? opt.label 
                : opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
              return {
                value: opt.value,
                label: labelValue
              };
            });
          } else if (typeof attr.options === 'string') {
            optionsReference = attr.options;
          }
        } else if (attr.type === 'multiselect') {
          fieldType = 'multiselect';
          // Handle options - can be array or string reference
          if (Array.isArray(attr.options)) {
            options = attr.options.map(opt => {
              const labelValue = typeof opt.label === 'string' 
                ? opt.label 
                : opt.label?.en || opt.label?.[Object.keys(opt.label)[0]] || String(opt.value);
              return {
                value: opt.value,
                label: labelValue
              };
            });
          } else if (typeof attr.options === 'string') {
            optionsReference = attr.options;
          }
        } else if (attr.type === 'textarea') {
          fieldType = 'textarea';
        } else if (attr.type === 'text') {
          // Check if it should be textarea based on name
          if (attr.name.toLowerCase().includes('description') || attr.name.toLowerCase().includes('note')) {
            fieldType = 'textarea';
          } else {
            fieldType = 'string';
          }
        }
        // Note: Legacy 'boolean' and 'enum' types are not in the AttributeDefinition type union
        // If needed, they should be handled via type casting: (attr as any).type === 'boolean'

        // Define validators and required fields
        let required = attr.required === true;
        let validator: ((value: any) => string | null) | undefined = undefined;
        let minRows: number | undefined = undefined;
        let maxRows: number | undefined = undefined;

        if (attr.name === 'name') {
          required = true;
          validator = (value: any) => {
            if (!value || (typeof value === 'string' && value.trim() === '')) {
              return 'Workflow name cannot be empty';
            }
            if (typeof value === 'string' && value.length > 100) {
              return 'Workflow name cannot exceed 100 characters';
            }
            return null;
          };
        } else if (fieldType === 'textarea') {
          minRows = 4;
          maxRows = 8;
        }
        // Multiselect validation
        else if (fieldType === 'multiselect' && required) {
          validator = (value: any[]) => {
            if (!value || !Array.isArray(value) || value.length === 0) {
              return `${attr.label} is required`;
            }
            return null;
          };
        }

        return {
          key: attr.name,
          label: attr.label || attr.name,
          type: fieldType,
          editable: attr.editable !== false && attr.readonly !== true,
          required,
          validator,
          minRows,
          maxRows,
          options,
          optionsReference
        };
      });

    return editableFields;
  }, [attributes]);

  // Ensure attributes are loaded - can be called by EditActionButton
  const ensureAttributesLoaded = useCallback(async () => {
    // If attributes are already loaded, return them
    if (attributes && attributes.length > 0) {
      return attributes;
    }
    
    // Otherwise, fetch them and return the result
    const fetchedAttributes = await fetchAttributes();
    return fetchedAttributes;
  }, [attributes, fetchAttributes]);

  // Fetch attributes and permissions on mount
  // Note: Do NOT fetch workflows here - let the table component control pagination
  useEffect(() => {
    fetchAttributes();
    fetchPermissions();
  }, [fetchAttributes, fetchPermissions]);

  // Listen for workflow creation events to refetch workflows list
  useEffect(() => {
    const handleWorkflowCreated = (_event: CustomEvent<{ workflow: UserWorkflow }>) => {
      // Refetch to ensure we have the latest data
      fetchWorkflowsData();
    };

    window.addEventListener('workflowCreated', handleWorkflowCreated as EventListener);
    
    return () => {
      window.removeEventListener('workflowCreated', handleWorkflowCreated as EventListener);
    };
  }, [fetchWorkflowsData]);

  return { 
    data: workflows, 
    loading, 
    error, 
    refetch: fetchWorkflowsData,
    removeOptimistically,
    updateOptimistically,
    attributes,
    permissions,
    pagination,
    fetchWorkflowById,
    generateEditFieldsFromAttributes,
    ensureAttributesLoaded
  };
}

// Workflow operations hook
export function useWorkflowOperations() {
  const [startingWorkflow, setStartingWorkflow] = useState(false);
  const [stoppingWorkflows, setStoppingWorkflows] = useState<Set<string>>(new Set());
  const [deletingWorkflows, setDeletingWorkflows] = useState<Set<string>>(new Set());
  const [editingWorkflows, setEditingWorkflows] = useState<Set<string>>(new Set());
  const [deletingMessages, setDeletingMessages] = useState<Set<string>>(new Set());
  const [deletingFiles, setDeletingFiles] = useState<Set<string>>(new Set());
  
  const [startError, setStartError] = useState<string | null>(null);
  const [stopError, setStopError] = useState<string | null>(null);
  const [deleteError, setDeleteError] = useState<string | null>(null);
  const [updateError, setUpdateError] = useState<string | null>(null);
  const [deleteMessageError, setDeleteMessageError] = useState<string | null>(null);
  const [deleteFileError, setDeleteFileError] = useState<string | null>(null);
  
  // Workflow selection context - to clear selection if deleted workflow is selected
  const { selectedWorkflowId, clearWorkflow } = useWorkflowSelection();
  
  const { request } = useApiRequest();
  
  // Generic delete operation handler
  const handleDeleteOperation = async <T>(
    operationKey: string,
    setLoadingSet: React.Dispatch<React.SetStateAction<Set<string>>>,
    setErrorState: React.Dispatch<React.SetStateAction<string | null>>,
    operation: () => Promise<T>,
    errorMessages: { default: string; notFound: string; forbidden: string }
  ): Promise<{ success: boolean; error?: string }> => {
    setErrorState(null);
    setLoadingSet(prev => new Set(prev).add(operationKey));
    
    try {
      await operation();
      return { success: true };
    } catch (error: any) {
      let errorMessage = error.message || errorMessages.default;
      
      if (error.response?.status === 404) {
        errorMessage = errorMessages.notFound;
        return { success: true };
      } else if (error.response?.status === 403) {
        errorMessage = errorMessages.forbidden;
      }
      
      setErrorState(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoadingSet(prev => {
        const newSet = new Set(prev);
        newSet.delete(operationKey);
        return newSet;
      });
    }
  };

  const startWorkflow = async (
    workflowData: StartWorkflowRequest, 
    options?: { workflowId?: string; workflowMode?: 'Dynamic' | 'Automation' }
  ) => {
    setStartError(null);
    setStartingWorkflow(true);
    
    try {
      const response = await startWorkflowApi(request, workflowData, options);
      return { success: true, data: response };
    } catch (error: any) {
      const errorMessage = error.message || 'Failed to start workflow';
      setStartError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setStartingWorkflow(false);
    }
  };

  const stopWorkflow = async (workflowId: string) => {
    setStopError(null);
    setStoppingWorkflows(prev => new Set(prev).add(workflowId));
    
    try {
      await stopWorkflowApi(request, workflowId);
      return { success: true };
    } catch (error: any) {
      const errorMessage = error.message || 'Failed to stop workflow';
      setStopError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setStoppingWorkflows(prev => {
        const newSet = new Set(prev);
        newSet.delete(workflowId);
        return newSet;
      });
    }
  };

  const handleWorkflowDelete = async (workflowId: string) => {
    const result = await handleDeleteOperation(
      workflowId,
      setDeletingWorkflows,
      setDeleteError,
      () => deleteWorkflowApi(request, workflowId),
      {
        default: 'Failed to delete workflow',
        notFound: 'Workflow not found or has already been deleted.',
        forbidden: 'No permission to delete this workflow.'
      }
    );

    if (result.success) {
      // Add a small delay to ensure backend has time to process
      await new Promise(resolve => setTimeout(resolve, 300));
      
      // Dispatch event to notify other components (e.g., dashboard dropdown)
      window.dispatchEvent(new CustomEvent('workflowDeleted', { 
        detail: { workflowIds: [workflowId] } 
      }));
      
      // Clear workflow selection if the deleted workflow was selected
      if (selectedWorkflowId === workflowId) {
        clearWorkflow();
      }
    }
    
    return result.success;
  };

  const handleWorkflowDeleteMultiple = async (workflowIds: string[]) => {
    setDeleteError(null);
    setDeletingWorkflows(prev => {
      const newSet = new Set(prev);
      workflowIds.forEach(id => newSet.add(id));
      return newSet;
    });
    
    try {
      // Delete workflows one by one since there's no bulk delete endpoint
      await deleteWorkflowsApi(request, workflowIds);

      // Add a small delay to ensure backend has time to process
      await new Promise(resolve => setTimeout(resolve, 300));
      
      // Dispatch event to notify other components (e.g., dashboard dropdown)
      window.dispatchEvent(new CustomEvent('workflowDeleted', { 
        detail: { workflowIds } 
      }));
      
      // Clear workflow selection if the selected workflow was deleted
      if (selectedWorkflowId && workflowIds.includes(selectedWorkflowId)) {
        clearWorkflow();
      }
      
      return true;
    } catch (error: any) {
      console.error(`❌ Bulk delete failed:`, error);
      setDeleteError(error.message || 'Bulk delete failed');
      return false;
    } finally {
      setDeletingWorkflows(prev => {
        const newSet = new Set(prev);
        workflowIds.forEach(id => newSet.delete(id));
        return newSet;
      });
    }
  };

  const deleteMessage = async (workflowId: string, messageId: string) => {
    const operationKey = `${workflowId}:${messageId}`;
    return handleDeleteOperation(
      operationKey,
      setDeletingMessages,
      setDeleteMessageError,
      () => deleteMessageApi(request, workflowId, messageId),
      {
        default: 'Failed to delete message',
        notFound: 'Message not found or has already been deleted.',
        forbidden: 'No permission to delete this message.'
      }
    );
  };

  const deleteFileFromMessage = async (
    workflowId: string, 
    messageId: string, 
    fileId: string
  ) => {
    const operationKey = `${workflowId}:${messageId}:${fileId}`;
    return handleDeleteOperation(
      operationKey,
      setDeletingFiles,
      setDeleteFileError,
      () => deleteFileFromMessageApi(request, workflowId, messageId, fileId),
      {
        default: 'Failed to delete file',
        notFound: 'File not found or has already been deleted.',
        forbidden: 'No permission to delete this file.'
      }
    );
  };

  const handleWorkflowUpdate = async (workflowId: string, updateData: Partial<{ name: string; description?: string; tags?: string[] }>, _originalWorkflowData?: any) => {
    setUpdateError(null);
    setEditingWorkflows(prev => new Set(prev).add(workflowId));
    
    try {
      const updatedWorkflow = await updateWorkflowApi(request, workflowId, updateData);
      
      return { success: true, workflowData: updatedWorkflow };
    } catch (error: any) {
      console.error(`Update failed for workflow ID ${workflowId}:`, error);
      
      const errorMessage = error.response?.data?.message || error.message || 'Failed to update workflow';
      const statusCode = error.response?.status;
      
      setUpdateError(errorMessage);
      
      // Return detailed error information for proper handling
      return { 
        success: false, 
        error: errorMessage,
        statusCode,
        isPermissionError: statusCode === 403,
        isValidationError: statusCode === 400
      };
    } finally {
      setEditingWorkflows(prev => {
        const newSet = new Set(prev);
        newSet.delete(workflowId);
        return newSet;
      });
    }
  };

  // Generic inline update handler for FormGeneratorTable
  // Must merge changes with existing row data because backend requires full object
  const handleInlineUpdate = async (workflowId: string, changes: Partial<UserWorkflow>, existingRow?: any) => {
    if (!existingRow) {
      throw new Error(`Existing row data required for inline update`);
    }
    
    // Merge changes with existing row data
    const mergedData = {
      name: existingRow.name,
      ...changes
    };
    
    const result = await handleWorkflowUpdate(workflowId, mergedData);
    if (!result.success) {
      throw new Error(result.error || 'Failed to update');
    }
    return result;
  };

  return {
    // Loading states
    startingWorkflow,
    stoppingWorkflows,
    deletingWorkflows,
    editingWorkflows,
    deletingMessages,
    deletingFiles,
    // Error states
    startError,
    stopError,
    deleteError,
    updateError,
    deleteMessageError,
    deleteFileError,
    // Operations
    startWorkflow,
    stopWorkflow,
    handleWorkflowDelete,
    handleWorkflowDeleteMultiple,
    handleWorkflowUpdate,
    handleInlineUpdate,
    deleteMessage,
    deleteFileFromMessage
  };
}
