import { useState, useCallback } from 'react';
import { useApiRequest } from './useApi';
import api from '../api';
import { usePermissions, type UserPermissions } from './usePermissions';
import {
    fetchAutomations as fetchAutomationsApi,
    fetchAutomation as fetchAutomationApi,
    createAutomationApi,
    updateAutomationApi,
    deleteAutomationApi,
    executeAutomationApi,
    fetchAutomationTemplates as fetchTemplatesApi,
    type Automation,
    type AutomationTemplate,
    type CreateAutomationRequest,
    type UpdateAutomationRequest
} from '../api/automationApi';

// Re-export types
export type { Automation, AutomationTemplate, CreateAutomationRequest, UpdateAutomationRequest };

// Attribute definition interface
export interface AttributeDefinition {
    name: string;
    type: 'text' | 'email' | 'date' | 'checkbox' | 'select' | 'multiselect' | 'number' | 'textarea';
    label: string;
    description?: string;
    required?: boolean;
    default?: any;
    options?: Array<{ value: string | number; label: string | { [key: string]: string } }> | string;
    validation?: any;
    readonly?: boolean;
    editable?: boolean;
    visible?: boolean;
    order?: number;
    sortable?: boolean;
    filterable?: boolean;
    searchable?: boolean;
    width?: number;
    minWidth?: number;
    maxWidth?: number;
    filterOptions?: string[];
}

// Automations list hook
export function useAutomations() {
    const [automations, setAutomations] = useState<Automation[]>([]);
    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, Automation[]>();
    const { checkPermission } = usePermissions();

    // Fetch attributes from backend - no fallback, errors should be visible
    const fetchAttributes = useCallback(async () => {
        try {
            const response = await api.get('/api/automations/attributes');
            
            let attrs: AttributeDefinition[] = [];
            // Backend returns: { attributes: { model: "...", attributes: [...] } }
            // So we need to access response.data.attributes.attributes
            if (response.data?.attributes?.attributes && Array.isArray(response.data.attributes.attributes)) {
                attrs = response.data.attributes.attributes;
            } else if (response.data?.attributes && Array.isArray(response.data.attributes)) {
                // Fallback: if attributes is directly an array
                attrs = response.data.attributes;
            } else if (Array.isArray(response.data)) {
                attrs = response.data;
            }
            
            if (attrs.length === 0) {
                console.warn('No attributes returned from backend for AutomationDefinition');
            }
            
            setAttributes(attrs);
            return attrs;
        } catch (error: any) {
            console.error('Error fetching automation attributes:', error);
            setAttributes([]);
            return [];
        }
    }, []);

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

    const fetchAutomations = useCallback(async () => {
        try {
            const data = await fetchAutomationsApi(request);
            
            // Handle paginated response
            if (data && typeof data === 'object' && 'items' in data) {
                const items = Array.isArray((data as any).items) ? (data as any).items : [];
                setAutomations(items);
                if ((data as any).pagination) {
                    setPagination((data as any).pagination);
                }
            } else {
                const items = Array.isArray(data) ? data : [];
                setAutomations(items);
                setPagination(null);
            }
        } catch (error: any) {
            setAutomations([]);
            setPagination(null);
        }
    }, [request]);

    // Optimistically remove an automation from the local state
    const removeOptimistically = (automationId: string) => {
        setAutomations(prev => prev.filter(a => a.id !== automationId));
    };

    // Optimistically update an automation in the local state
    const updateOptimistically = (automationId: string, updateData: Partial<Automation>) => {
        setAutomations(prev =>
            prev.map(a => a.id === automationId ? { ...a, ...updateData } : a)
        );
    };

    // Fetch a single automation by ID
    const fetchAutomationById = useCallback(async (automationId: string): Promise<Automation | null> => {
        try {
            return await fetchAutomationApi(request, automationId);
        } catch (error) {
            console.error('Error fetching automation 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;
        minRows?: number;
        maxRows?: number;
        options?: Array<{ value: string | number; label: string }>;
    }> => {
        if (!attributes || attributes.length === 0) {
            return [];
        }
        
        // Fields to show in edit form
        const editableFields = ['label', 'schedule', 'template', 'placeholders', 'active'];
        
        return attributes
            .filter(attr => editableFields.includes(attr.name) && attr.editable !== false)
            .map(attr => {
                let fieldType: 'string' | 'boolean' | 'textarea' | 'enum' | 'readonly' = 'string';
                
                if (attr.type === 'checkbox') {
                    fieldType = 'boolean';
                } else if (attr.type === 'textarea' || attr.name === 'template' || attr.name === 'placeholders') {
                    fieldType = 'textarea';
                } else if (attr.type === 'select' && attr.options) {
                    fieldType = 'enum';
                }
                
                const field: any = {
                    key: attr.name,
                    label: attr.label || attr.name,
                    type: fieldType,
                    editable: attr.editable !== false,
                    required: attr.required || false,
                };
                
                if (fieldType === 'textarea') {
                    field.minRows = 3;
                    field.maxRows = 15;
                }
                
                if (fieldType === 'enum' && attr.options) {
                    field.options = Array.isArray(attr.options) 
                        ? attr.options.map(opt => ({
                            value: typeof opt === 'object' ? opt.value : opt,
                            label: typeof opt === 'object' 
                                ? (typeof opt.label === 'object' ? opt.label['en'] || opt.label['de'] : opt.label)
                                : opt
                        }))
                        : [];
                }
                
                return field;
            });
    }, [attributes]);

    // Generate create fields from attributes
    const generateCreateFieldsFromAttributes = useCallback(() => {
        return generateEditFieldsFromAttributes();
    }, [generateEditFieldsFromAttributes]);

    // Ensure attributes are loaded
    const ensureAttributesLoaded = useCallback(async () => {
        if (attributes.length === 0) {
            await fetchAttributes();
        }
    }, [attributes.length, fetchAttributes]);

    // Initial data fetch
    const refetch = useCallback(async () => {
        await Promise.all([
            fetchAutomations(),
            fetchAttributes(),
            fetchPermissions()
        ]);
    }, [fetchAutomations, fetchAttributes, fetchPermissions]);

    return {
        automations,
        data: automations, // Alias for FormGenerator compatibility
        loading,
        error,
        refetch,
        removeOptimistically,
        updateOptimistically,
        attributes,
        permissions,
        pagination,
        fetchAutomationById,
        generateEditFieldsFromAttributes,
        generateCreateFieldsFromAttributes,
        ensureAttributesLoaded
    };
}

// Automation operations hook
export function useAutomationOperations() {
    const { request } = useApiRequest();
    const [deletingAutomations, setDeletingAutomations] = useState<Set<string>>(new Set());
    const [creatingAutomation, setCreatingAutomation] = useState(false);
    const [executingAutomations, setExecutingAutomations] = useState<Set<string>>(new Set());
    const [deleteError, setDeleteError] = useState<string | null>(null);
    const [createError, setCreateError] = useState<string | null>(null);
    const [updateError, setUpdateError] = useState<string | null>(null);

    // Create a new automation
    const handleAutomationCreate = useCallback(async (data: CreateAutomationRequest): Promise<Automation | null> => {
        setCreatingAutomation(true);
        setCreateError(null);
        
        try {
            // Validate required fields - mandateId and featureInstanceId must be provided
            if (!data.mandateId || !data.featureInstanceId) {
                throw new Error('mandateId and featureInstanceId are required');
            }
            
            // Convert placeholders to ensure all values are strings
            if (data.placeholders) {
                const convertedPlaceholders: Record<string, string> = {};
                for (const [key, value] of Object.entries(data.placeholders)) {
                    if (value === null || value === undefined) {
                        convertedPlaceholders[key] = '';
                    } else if (typeof value === 'object') {
                        convertedPlaceholders[key] = JSON.stringify(value);
                    } else {
                        convertedPlaceholders[key] = String(value);
                    }
                }
                data.placeholders = convertedPlaceholders;
            }
            
            const newAutomation = await createAutomationApi(request, data);
            return newAutomation;
        } catch (error: any) {
            console.error('Error creating automation:', error);
            setCreateError(error.message || 'Failed to create automation');
            return null;
        } finally {
            setCreatingAutomation(false);
        }
    }, [request]);

    // Update an existing automation
    const handleAutomationUpdate = useCallback(async (
        automationId: string,
        data: UpdateAutomationRequest
    ): Promise<boolean> => {
        setUpdateError(null);
        
        try {
            await updateAutomationApi(request, automationId, data);
            return true;
        } catch (error: any) {
            console.error('Error updating automation:', error);
            setUpdateError(error.message || 'Failed to update automation');
            return false;
        }
    }, [request]);

    // Delete an automation
    const handleAutomationDelete = useCallback(async (automationId: string): Promise<boolean> => {
        setDeletingAutomations(prev => new Set(prev).add(automationId));
        setDeleteError(null);
        
        try {
            await deleteAutomationApi(request, automationId);
            return true;
        } catch (error: any) {
            console.error('Error deleting automation:', error);
            setDeleteError(error.message || 'Failed to delete automation');
            return false;
        } finally {
            setDeletingAutomations(prev => {
                const newSet = new Set(prev);
                newSet.delete(automationId);
                return newSet;
            });
        }
    }, [request]);

    // Execute an automation
    const handleAutomationExecute = useCallback(async (automationId: string): Promise<any> => {
        setExecutingAutomations(prev => new Set(prev).add(automationId));
        
        try {
            const result = await executeAutomationApi(request, automationId);
            return result;
        } catch (error: any) {
            console.error('Error executing automation:', error);
            throw error;
        } finally {
            setExecutingAutomations(prev => {
                const newSet = new Set(prev);
                newSet.delete(automationId);
                return newSet;
            });
        }
    }, [request]);

    // Toggle automation active status
    // NOTE: Backend PUT expects full AutomationDefinition object including id
    const handleAutomationToggleActive = useCallback(async (
        automationId: string,
        currentActive: boolean,
        fullAutomation?: Automation
    ): Promise<boolean> => {
        try {
            // Build full update data - backend expects AutomationDefinition with all fields
            const sourceAutomation = fullAutomation || await fetchAutomationApi(request, automationId);
            
            // Backend requires id in body to match URL parameter
            const updateData = {
                id: automationId, // MUST match URL parameter
                mandateId: sourceAutomation.mandateId,
                featureInstanceId: sourceAutomation.featureInstanceId,
                label: sourceAutomation.label,
                schedule: sourceAutomation.schedule,
                template: typeof sourceAutomation.template === 'object' 
                    ? JSON.stringify(sourceAutomation.template) 
                    : sourceAutomation.template,
                placeholders: sourceAutomation.placeholders || {},
                active: !currentActive
            };
            
            await updateAutomationApi(request, automationId, updateData as any);
            return true;
        } catch (error: any) {
            console.error('Error toggling automation active status:', error);
            return false;
        }
    }, [request]);

    // Generic inline update handler for FormGeneratorTable
    // NOTE: Backend PUT requires full object, so we merge changes with existing row data
    const handleInlineUpdate = useCallback(async (
        automationId: string,
        changes: Partial<Automation>,
        existingRow?: Automation
    ) => {
        if (!existingRow) {
            throw new Error('Existing row data required for inline update');
        }
        
        try {
            // Merge changes with existing row data and send all required fields
            const updateData = {
                id: automationId, // MUST match URL parameter
                mandateId: existingRow.mandateId,
                featureInstanceId: existingRow.featureInstanceId,
                label: existingRow.label,
                schedule: existingRow.schedule,
                template: typeof existingRow.template === 'object' 
                    ? JSON.stringify(existingRow.template) 
                    : existingRow.template,
                placeholders: existingRow.placeholders || {},
                // Apply the changes (e.g., active: true/false)
                ...changes
            };
            
            await updateAutomationApi(request, automationId, updateData as any);
            return { success: true };
        } catch (error: any) {
            console.error('Error in inline update:', error);
            throw new Error(error.message || 'Failed to update');
        }
    }, [request]);

    // Fetch templates
    const fetchTemplates = useCallback(async (): Promise<AutomationTemplate[]> => {
        try {
            return await fetchTemplatesApi(request);
        } catch (error: any) {
            console.error('Error fetching templates:', error);
            return [];
        }
    }, [request]);

    return {
        handleAutomationCreate,
        handleAutomationUpdate,
        handleAutomationDelete,
        handleAutomationExecute,
        handleAutomationToggleActive,
        handleInlineUpdate,
        fetchTemplates,
        deletingAutomations,
        creatingAutomation,
        executingAutomations,
        deleteError,
        createError,
        updateError
    };
}
