import { useState, useEffect, useCallback } from 'react';
import { useApiRequest } from './useApi';
import api from '../api';
import { usePermissions, type UserPermissions } from './usePermissions';
import {
  fetchPrompts as fetchPromptsApi,
  fetchPromptById as fetchPromptByIdApi,
  createPrompt as createPromptApi,
  updatePrompt as updatePromptApi,
  deletePrompt as deletePromptApi,
  type Prompt,
  type AttributeDefinition,
  type PaginationParams
} from '../api/promptApi';

// Re-export types for backward compatibility
export type { Prompt, AttributeDefinition, PaginationParams };

// Re-export AttributeOption for backward compatibility
export interface AttributeOption {
  value: string | number;
  label: string | { [key: string]: string };
}

// Prompts list hook
export function usePrompts() {
  const [prompts, setPrompts] = useState<Prompt[]>([]);
  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, Prompt[]>();
  const { checkPermission } = usePermissions();

  // Fetch attributes from backend
  const fetchAttributes = useCallback(async () => {
    try {
      const response = await api.get('/api/attributes/Prompt');
      
      // Extract attributes from response - check if response.data.attributes exists, otherwise check if response.data is an array
      let attrs: AttributeDefinition[] = [];
      if (response.data?.attributes && Array.isArray(response.data.attributes)) {
        attrs = response.data.attributes;
      } else if (Array.isArray(response.data)) {
        attrs = response.data;
      } else if (response.data && typeof response.data === 'object') {
        // Try to find any array property in the response
        const keys = Object.keys(response.data);
        for (const key of keys) {
          if (Array.isArray(response.data[key])) {
            attrs = response.data[key];
            break;
          }
        }
      }
      
      setAttributes(attrs);
      return attrs;
    } catch (error: any) {
      console.error('Error fetching attributes:', error);
      setAttributes([]);
      return [];
    }
  }, []);

  // Fetch permissions from backend
  const fetchPermissions = useCallback(async () => {
    try {
      const perms = await checkPermission('DATA', 'Prompt');
      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 fetchPrompts = useCallback(async (params?: PaginationParams) => {
    try {
      const data = await fetchPromptsApi(request, params);
      
      // Handle paginated response
      if (data && typeof data === 'object' && 'items' in data) {
        const items = Array.isArray(data.items) ? data.items : [];
        setPrompts(items);
        if (data.pagination) {
          setPagination(data.pagination);
        }
      } else {
        // Handle non-paginated response (backward compatibility)
        const items = Array.isArray(data) ? data : [];
        setPrompts(items);
        setPagination(null);
      }
    } catch (error: any) {
      // Error is already handled by useApiRequest
      setPrompts([]);
      setPagination(null);
    }
  }, [request]);

  // Optimistically remove a prompt from the local state
  const removeOptimistically = (promptId: string) => {
    setPrompts(prevPrompts => prevPrompts.filter(prompt => prompt.id !== promptId));
  };

  // Optimistically update a prompt in the local state
  const updateOptimistically = (promptId: string, updateData: { name: string; content: string }) => {
    setPrompts(prevPrompts => 
      prevPrompts.map(prompt => 
        prompt.id === promptId 
          ? { ...prompt, ...updateData }
          : prompt
      )
    );
  };

  // Fetch a single prompt by ID
  const fetchPromptById = useCallback(async (promptId: string): Promise<Prompt | null> => {
    return await fetchPromptByIdApi(request, promptId);
  }, [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 => {
        // Check if this is a content field first - check this BEFORE type mapping
        const isContentField = attr.name === 'content' || 
                               attr.name.toLowerCase().includes('content') || 
                               attr.name.toLowerCase().includes('description');
        
        // Map backend attribute type to form field type
        // IMPORTANT: Check for content fields FIRST before other type checks
        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;
        
        if (isContentField) {
          // Force content fields to ALWAYS be textarea, regardless of attribute type
          fieldType = 'textarea';
        } else 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('text') || 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;

        // Match create button configuration for prompts
        if (attr.name === 'name') {
          required = true;
          validator = (value: any) => {
            if (!value || (typeof value === 'string' && value.trim() === '')) {
              return 'Prompt name cannot be empty';
            }
            if (typeof value === 'string' && value.length > 100) {
              return 'Prompt name cannot exceed 100 characters';
            }
            return null;
          };
        } else if (isContentField || attr.name === 'content') {
          required = true;
          minRows = 6; // Match create button: minRows: 6
          maxRows = 12; // Match create button: maxRows: 12
          validator = (value: any) => {
            if (!value || (typeof value === 'string' && value.trim() === '')) {
              return 'Prompt content cannot be empty';
            }
            if (typeof value === 'string' && value.length > 10000) {
              return 'Prompt content cannot exceed 10,000 characters';
            }
            return null;
          };
        } else if (fieldType === 'textarea') {
          // Default textarea settings for other textarea fields
          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
        };
      });

    // Ensure we always return at least the basic fields if attributes exist
    // This handles cases where all fields might be filtered out
    if (editableFields.length === 0 && attributes.length > 0) {
      // If all fields were filtered out, include all attributes as editable string fields
      // Match create button configuration
      return attributes.map(attr => {
        const isContentField = attr.name === 'content' || attr.name.toLowerCase().includes('content');
        const fieldType = isContentField ? 'textarea' as const : 'string' as const;
        
        let required = false;
        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 'Prompt name cannot be empty';
            }
            if (typeof value === 'string' && value.length > 100) {
              return 'Prompt name cannot exceed 100 characters';
            }
            return null;
          };
        } else if (isContentField) {
          required = true;
          minRows = 6; // Match create button
          maxRows = 12; // Match create button
          validator = (value: any) => {
            if (!value || (typeof value === 'string' && value.trim() === '')) {
              return 'Prompt content cannot be empty';
            }
            if (typeof value === 'string' && value.length > 10000) {
              return 'Prompt content cannot exceed 10,000 characters';
            }
            return null;
          };
        }

        return {
          key: attr.name,
          label: attr.label || attr.name,
          type: fieldType,
          editable: true,
          required,
          validator,
          minRows,
          maxRows
        };
      });
    }

    return editableFields;
  }, [attributes]);

  // Generate create fields from attributes dynamically
  // For prompts, the create form is essentially the same as edit form
  const generateCreateFieldsFromAttributes = useCallback((): Array<{
    key: string;
    label: string;
    type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'multiselect' | 'readonly';
    required?: boolean;
    validator?: (value: any) => string | null;
    minRows?: number;
    maxRows?: number;
    options?: Array<{ value: string | number; label: string }>;
    optionsReference?: string;
    placeholder?: string;
  }> => {
    if (!attributes || attributes.length === 0) {
      return [];
    }

    const createFields = attributes
      .filter(attr => {
        // Filter out non-editable fields and auto-generated fields for create forms
        if (attr.readonly === true || attr.editable === false) {
          return false;
        }
        // Filter out ID fields and other auto-generated 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 minRows: number | undefined = undefined;
        let maxRows: number | undefined = undefined;
        
        // Map backend types to form field types
        // Cast to string to handle all possible backend type values
        const attrType = attr.type as string;
        if (attrType === 'checkbox' || attrType === 'boolean') {
          fieldType = 'boolean';
        } else if (attrType === 'email') {
          fieldType = 'email';
        } else if (attrType === 'timestamp' || attrType === 'date' || attrType === 'time') {
          fieldType = 'date';
        } else if (attrType === 'textarea') {
          fieldType = 'textarea';
          // Set default rows for textarea fields
          minRows = 6;
          maxRows = 12;
        } else if (attr.name === 'content' || attr.name.toLowerCase().includes('content')) {
          // Content fields should be textarea
          fieldType = 'textarea';
          minRows = 6;
          maxRows = 12;
        }
        
        // Determine if required and build validator
        const required = attr.required === true;
        let validator: ((value: any) => string | null) | undefined = undefined;
        
        // Required string validation
        if (required && (fieldType === 'string' || fieldType === 'textarea')) {
          validator = (value: any) => {
            if (!value || (typeof value === 'string' && value.trim() === '')) {
              return `${attr.label} is required`;
            }
            if (attr.name === 'name' && typeof value === 'string' && value.length > 100) {
              return 'Prompt name cannot exceed 100 characters';
            }
            if (attr.name === 'content' && typeof value === 'string' && value.length > 10000) {
              return 'Prompt content cannot exceed 10,000 characters';
            }
            return null;
          };
        }

        return {
          key: attr.name,
          label: attr.label || attr.name,
          type: fieldType,
          required,
          validator,
          minRows,
          maxRows
        };
      });

    return createFields;
  }, [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
  useEffect(() => {
    fetchAttributes();
    fetchPermissions();
  }, [fetchAttributes, fetchPermissions]);

  // Initial fetch
  useEffect(() => {
    fetchPrompts();
  }, [fetchPrompts]);

  return { 
    prompts, 
    loading, 
    error, 
    refetch: fetchPrompts,
    removeOptimistically,
    updateOptimistically,
    attributes,
    permissions,
    pagination,
    fetchPromptById,
    generateEditFieldsFromAttributes,
    generateCreateFieldsFromAttributes,
    ensureAttributesLoaded // Generic function to ensure attributes are loaded
  };
}

// Prompt operations hook
export function usePromptOperations() {
  const [deletingPrompts, setDeletingPrompts] = useState<Set<string>>(new Set());
  const [creatingPrompt, setCreatingPrompt] = useState(false);
  const { request, isLoading } = useApiRequest();
  const [deleteError, setDeleteError] = useState<string | null>(null);
  const [createError, setCreateError] = useState<string | null>(null);
  const [updateError, setUpdateError] = useState<string | null>(null);

  const handlePromptDelete = async (promptId: string) => {
    setDeleteError(null);
    setDeletingPrompts(prev => new Set(prev).add(promptId));
    
    try {
      await deletePromptApi(request, promptId);
      
      // Add a small delay to ensure backend has time to process
      await new Promise(resolve => setTimeout(resolve, 300));
      return true;
    } catch (error: any) {
      setDeleteError(error.message);
      return false;
    } finally {
      setDeletingPrompts(prev => {
        const newSet = new Set(prev);
        newSet.delete(promptId);
        return newSet;
      });
    }
  };

  const handlePromptCreate = async (promptData: { name: string; content: string }) => {
    setCreateError(null);
    setCreatingPrompt(true);
    
    try {
      // mandateId wird nicht mehr vom Client gesendet
      // Das Backend bestimmt den Kontext über die instanceId im Request
      const requestBody = {
        name: promptData.name,
        content: promptData.content
      };
      
      const newPrompt = await createPromptApi(request, requestBody);
      
      return { success: true, promptData: newPrompt };
    } catch (error: any) {
      setCreateError(error.message);
      return { success: false, error: error.message };
    } finally {
      setCreatingPrompt(false);
    }
  };

  const handlePromptUpdate = async (promptId: string, updateData: { name: string; content: string }, _originalData?: any) => {
    setUpdateError(null);
    
    try {
      // mandateId wird nicht mehr vom Client gesendet
      const requestBody = {
        name: updateData.name,
        content: updateData.content
      };
      
      const updatedPrompt = await updatePromptApi(request, promptId, requestBody);
      
      return { success: true, promptData: updatedPrompt };
    } catch (error: any) {
      const errorMessage = error.response?.data?.message || error.message || 'Failed to update prompt';
      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
      };
    }
  };

  // Generic inline update handler for FormGeneratorTable
  const handleInlineUpdate = async (promptId: string, changes: Partial<{ name: string; content: string }>) => {
    const result = await handlePromptUpdate(promptId, changes as { name: string; content: string });
    if (!result.success) {
      throw new Error(result.error || 'Failed to update');
    }
    return result;
  };

  return {
    deletingPrompts,
    creatingPrompt,
    deleteError,
    createError,
    updateError,
    handlePromptDelete,
    handlePromptCreate,
    handlePromptUpdate,
    handleInlineUpdate,
    isLoading
  };
} 