import { createContext, useContext, useState, useEffect, useRef } from 'react';

const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000';

const NomenclatureContext = createContext();

// Centralized nomenclature configuration
const NOMENCLATURES_CONFIG = [
    { key: 'vehicles', jsonKey: 'vehicles', sortBy: 'name', endpoint: '/api/vehicles/', sseObjectType: 'vehicle' },
    // { key: 'vesselOwners', jsonKey: 'vessel_owners', sortBy: 'name', endpoint: '/vessel_owners/api/list/', sseObjectType: 'vessel_owner' },
    // { key: 'agents', jsonKey: 'agents', sortBy: 'name', endpoint: '/agents/api/list/', sseObjectType: 'agent' },
    // { key: 'objects', jsonKey: 'objects', sortBy: 'id', endpoint: '/objects/api/list/', sseObjectType: 'object' },
    // { key: 'cargos', jsonKey: 'cargos', sortBy: 'name', endpoint: '/cargos/api/list/', sseObjectType: 'cargo' },
    // { key: 'groups', jsonKey: 'groups', sortBy: 'id', endpoint: '/groups/api/list/', sseObjectType: 'group' },
    // { key: 'groupSmalls', jsonKey: 'groupsmalls', sortBy: 'id', endpoint: '/groups/api/getgroupsmalls/', sseObjectType: 'groupsmalls' },
    // { key: 'tariffs', jsonKey: 'tariffs', sortBy: 'id', endpoint: '/tariff/api/list/', sseObjectType: 'tariff' },
    // { key: 'tariffSmalls', jsonKey: 'tariffsmalls', sortBy: 'id', endpoint: '/tariff/api/tariffsmalls', sseObjectType: 'tariffsmalls' },
    // { key: 'countries', jsonKey: 'countries', sortBy: 'name', endpoint: '/countries/api/list', sseObjectType: 'country' },
    // { key: 'passThroughs', jsonKey: 'passthroughs', sortBy: 'id', endpoint: '/tariff/api/getpassthroughs/', sseObjectType: 'passthrough' },
    // { key: 'vats', jsonKey: 'vats', sortBy: 'id', endpoint: '/tariff/api/getvats/', sseObjectType: 'vat' },
    // { key: 'maneuvers', jsonKey: 'maneuvers', sortBy: 'id', endpoint: '/common/api/maneuvers/', sseObjectType: 'maneuver' },
    // { key: 'prices', jsonKey: 'prices', sortBy: 'id', endpoint: '/tariff/api/prices/', sseObjectType: 'prices' },
    // { key: 'bankAccounts', jsonKey: 'bank_accounts', sortBy: 'id', endpoint: '/common/api/bank-accounts/', sseObjectType: 'bank_account' },
    // { key: 'noticeNotes', jsonKey: 'notice_notes', sortBy: 'name', endpoint: '/invoices/api/notice-notes/list/', sseObjectType: 'notice_note' },
    // { key: 'translations', jsonKey: 'translations', sortBy: 'name', endpoint: '/common/api/translations/', sseObjectType: 'translation' }
];

// Helper function to get config for a specific key
const getConfigForKey = (key) => NOMENCLATURES_CONFIG.find(c => c.key === key);

// Helper function to get nomenclature key from SSE object type
const getNomenclatureKeyFromSSE = (sseObjectType) => {
    const config = NOMENCLATURES_CONFIG.find(c => c.sseObjectType === sseObjectType);
    return config?.key;
};

export const useNomenclatures = () => {
    const context = useContext(NomenclatureContext);
    if (!context) {
        throw new Error('useNomenclatures must be used within a NomenclatureProvider');
    }
    return context;
};

// Utility function to sort nomenclature array based on configuration
const sortNomenclature = (array, nomenclatureKey) => {
    const config = getConfigForKey(nomenclatureKey);
    const orderBy = config?.sortBy || 'name';

    return [...array].sort((a, b) => {
        if (orderBy === 'id') {
            return (a.id || 0) - (b.id || 0);
        } else {
            // Order by name (case-insensitive)
            const nameA = (a.name || '').toLowerCase();
            const nameB = (b.name || '').toLowerCase();
            return nameA.localeCompare(nameB);
        }
    });
};

// Utility function to insert item in sorted position
const insertSorted = (array, newItem, nomenclatureKey) => {
    const config = getConfigForKey(nomenclatureKey);
    const orderBy = config?.sortBy || 'name';
    const newArray = [...array];

    // Find the correct insertion position
    let insertIndex = newArray.length;

    if (orderBy === 'id') {
        insertIndex = newArray.findIndex(item => {
            const comparison = item.id > newItem.id;
            return comparison;
        });
        if (insertIndex === -1) insertIndex = newArray.length;

    } else {
        const newName = (newItem.name || '').toLowerCase();
        insertIndex = newArray.findIndex(item =>
            (item.name || '').toLowerCase() > newName
        );
        if (insertIndex === -1) insertIndex = newArray.length;
    }

    newArray.splice(insertIndex, 0, newItem);
    return newArray;
};

// Utility function to update item and maintain sorted order
const updateSorted = (array, updatedItem, nomenclatureKey) => {
    const config = getConfigForKey(nomenclatureKey);
    const orderBy = config?.sortBy || 'name';

    // Remove the old item
    const filteredArray = array.filter(item => item.id !== updatedItem.id);

    // Check if the ordering field has changed
    const oldItem = array.find(item => item.id === updatedItem.id);
    if (!oldItem) {
        // Item not found, just insert it
        return insertSorted(filteredArray, updatedItem, nomenclatureKey);
    }

    const orderFieldChanged = orderBy === 'id'
        ? oldItem.id !== updatedItem.id
        : (oldItem.name || '').toLowerCase() !== (updatedItem.name || '').toLowerCase();

    if (orderFieldChanged) {
        // Re-insert in sorted position if the ordering field changed
        return insertSorted(filteredArray, updatedItem, nomenclatureKey);
    } else {
        // Just update in place if ordering hasn't changed
        return array.map(item =>
            item.id === updatedItem.id ? { ...item, ...updatedItem } : item
        );
    }
};

// Generate initial state objects from config
const generateInitialState = () => NOMENCLATURES_CONFIG.reduce((acc, config) => {
    acc[config.key] = [];
    return acc;
}, {});

const generateInitialLoadingState = () => NOMENCLATURES_CONFIG.reduce((acc, config) => {
    acc[config.key] = false;
    return acc;
}, {});

const generateInitialErrorState = () => NOMENCLATURES_CONFIG.reduce((acc, config) => {
    acc[config.key] = null;
    return acc;
}, {});

export const NomenclatureProvider = ({ children }) => {
    // Ref to track invoice update subscribers
    const subscribersRef = useRef(new Set());

    const [nomenclatures, setNomenclatures] = useState(generateInitialState());
    const [loading, setLoading] = useState(generateInitialLoadingState());
    const [error, setError] = useState(generateInitialErrorState());
    const [allLoaded, setAllLoaded] = useState(false);
    const [hasStartedLoading, setHasStartedLoading] = useState(false);

    // Generic fetch function
    const fetchNomenclature = async (key, url) => {
        const startTime = performance.now();

        try {
            const token = localStorage.getItem('accessToken');
            const headers = {
                'Content-Type': 'application/json',
            };

            if (token) {
                headers['Authorization'] = `Bearer ${token}`;
            }

            const response = await fetch(url, {
                headers,
                credentials: 'include'
            });

            if (!response.ok) {
                throw new Error(`Failed to fetch ${key}: ${response.status} ${response.statusText}`);
            }

            const data = await response.json();

            if (data && typeof data === 'object') {

            }

            // Normalize data format - adjust based on your API response structure
            let normalizedData;
            if (Array.isArray(data)) {
                normalizedData = data;
            } else if (data && typeof data === 'object') {
                // Handle different response formats
                const config = getConfigForKey(key);
                const jsonKey = config?.jsonKey; // Get the correct JSON key from config
                normalizedData = data.results || data.data || data[jsonKey] || data[key] || [];
            } else {
                normalizedData = [];
            }

            // Sort the data according to configured order
            const sortedData = sortNomenclature(normalizedData, key);

            setNomenclatures(prev => ({
                ...prev,
                [key]: sortedData
            }));

            setError(prev => ({
                ...prev,
                [key]: null
            }));

        } catch (err) {
            const totalTime = performance.now() - startTime;
            console.error(`❌ [${key}] Failed after ${totalTime.toFixed(2)}ms:`, err.message);
            setError(prev => ({
                ...prev,
                [key]: err.message
            }));
        } finally {
            setLoading(prev => ({
                ...prev,
                [key]: false
            }));
        }
    };

    // Load all nomenclatures on mount, but only if we have auth
    useEffect(() => {
        const loadAllNomenclatures = async () => {
            // Check if we have an auth token
            const token = localStorage.getItem('accessToken');
            if (!token) {
                return;
            }

            setHasStartedLoading(true);

            // Set all loading states to true
            const allLoadingState = NOMENCLATURES_CONFIG.reduce((acc, config) => {
                acc[config.key] = true;
                return acc;
            }, {});
            setLoading(allLoadingState);

            // Load all nomenclatures in parallel
            const promises = NOMENCLATURES_CONFIG.map(config =>
                fetchNomenclature(config.key, API_BASE_URL + config.endpoint)
            );

            await Promise.allSettled(promises);
/*
            // Wait a tick for state to update, then apply translations
            setTimeout(async () => {
                try {
                    // Fetch translations directly from API to ensure we have the latest data
                    const token = localStorage.getItem('authToken');
                    const translationsConfig = getConfigForKey('translations');
                    const response = await fetch(translationsConfig.endpoint, {
                        headers: {
                            'Content-Type': 'application/json',
                            'Authorization': `Token ${token}`
                        },
                        credentials: 'include'
                    });

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

                        if (translationsData && translationsData.length > 0) {
                            // Dynamic import to avoid circular dependency
                            const module = await import('@utils/printTranslations');
                            const { translationService } = await import('@services/translationService');
                            const merged = translationService.applyOverrides(
                                module.printTranslations,
                                translationsData
                            );
                            Object.assign(module.printTranslations, merged);
                            console.log('✅ Translations initialized:', translationsData.length, 'translations loaded');
                        }
                    }
                } catch (error) {
                    console.error('Failed to apply translation overrides:', error);
                }
            }, 100);
*/

            setAllLoaded(true);
        };
        loadAllNomenclatures();

        // Also listen for auth token changes
        const handleStorageChange = (e) => {
            if (e.key === 'accessToken' && e.newValue && !hasStartedLoading) {
                loadAllNomenclatures();
            }
        };

        window.addEventListener('storage', handleStorageChange);
        return () => window.removeEventListener('storage', handleStorageChange);
    }, [hasStartedLoading]);

    // SSE connection for real-time updates with auto-reconnect
    useEffect(() => {
        const token = localStorage.getItem('accessToken');
        if (!token) {
            return; // Don't connect if not authenticated
        }

        let eventSource;
        let reconnectTimeout;
        let isIntentionallyClosed = false;

        const connect = () => {
            if (isIntentionallyClosed) return;

            eventSource = new EventSource(`${API_BASE_URL}/sse-connect/?token=${token}`);

            eventSource.onopen = () => {
                // console.log('SSE connection opened');
            };

            eventSource.onmessage = (event) => {
                try {
                    const message = JSON.parse(event.data);
                    handleSSEUpdate(message);
                } catch (error) {
                    console.error('Error parsing SSE message:', error);
                }
            };

            eventSource.onerror = (error) => {
                console.error('SSE connection error:', error);
                eventSource.close();

                // Reconnect after 5 seconds
                if (!isIntentionallyClosed) {
                    console.log('SSE will reconnect in 5 seconds...');
                    reconnectTimeout = setTimeout(connect, 5000);
                }
            };
        };

        // Start initial connection
        connect();

        // Cleanup on unmount
        return () => {
            isIntentionallyClosed = true;
            if (reconnectTimeout) clearTimeout(reconnectTimeout);
            if (eventSource) eventSource.close();
        };
    }, []);

    // Function to subscribe to invoice updates
    const subscribeToUpdates = (callback) => {
        subscribersRef.current.add(callback);

        // Return unsubscribe function
        return () => {
            subscribersRef.current.delete(callback);
        };
    };

    // Handle SSE updates
    const handleSSEUpdate = (message) => {
        if (message.type !== 'data_update') {
            return; // Only handle data_update messages
        }

        const { object, operation, data } = message;

        // Handle nomenclature definition and entry updates - notify all subscribers
        if (object === 'nomenclature' || object === 'nomenclature_entry') {
            subscribersRef.current.forEach(callback => {
                try {
                    callback(message);
                } catch (error) {
                    console.error('Error in nomenclature entry update subscriber:', error);
                }
            });
            return;
        }

        // Handle invoice updates - notify all subscribers
        if (object === 'invoice' || object === 'notice') {
            subscribersRef.current.forEach(callback => {
                try {
                    callback(message);
                } catch (error) {
                    console.error('Error in invoice update subscriber:', error);
                }
            });
            return;
        }

        // Map object types to nomenclature keys using config
        const nomenclatureKey = getNomenclatureKeyFromSSE(object);
        if (!nomenclatureKey) {
            console.warn('Unknown object type in SSE update:', object);
            return;
        }

        // Special handling for translations: update printTranslations in real-time
        // if (nomenclatureKey === 'translations' && (operation === 'insert' || operation === 'update')) {
        //     import('@utils/printTranslations').then(async (module) => {
        //         const key = data.key;
        //         if (module.printTranslations[key]) {
        //             module.printTranslations[key] = {
        //                 bg: data.text_bg,
        //                 en: data.text_en
        //             };
        //         }
        //     }).catch(error => {
        //         console.error('Failed to update printTranslations from SSE:', error);
        //     });
        // }

        setNomenclatures(prev => {
            const currentArray = prev[nomenclatureKey] || [];

            if (operation === 'insert') {
                // Add new item if it doesn't exist
                const exists = currentArray.some(item => item.id === data.id);
                if (!exists) {
                    // Insert in sorted position
                    const sortedArray = insertSorted(currentArray, data, nomenclatureKey);
                    return {
                        ...prev,
                        [nomenclatureKey]: sortedArray
                    };
                }
                return prev;
            } else if (operation === 'update') {
                // Update existing item and maintain sort order
                const updatedArray = updateSorted(currentArray, data, nomenclatureKey);
                return {
                    ...prev,
                    [nomenclatureKey]: updatedArray
                };
            }

            return prev;
        });
    };

    const value = {
        // Spread all nomenclature data
        ...nomenclatures,

        // Loading states
        loading,
        allLoaded,

        // Error states
        error,

        // Utility functions
        subscribeToUpdates,

        // State helpers
        hasStartedLoading,

        // Helper to check if any is loading
        isAnyLoading: Object.values(loading).some(Boolean),

        // Helper to check if any has errors
        hasErrors: Object.values(error).some(Boolean)
    };

    return (
        <NomenclatureContext.Provider value={value}>
            {children}
        </NomenclatureContext.Provider>
    );
};
