import { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';
import api from '../services/api';
import { useNomenclatures } from './NomenclatureContext';

const NomenclatureDataContext = createContext();

export const useNomenclatureData = () => {
    const context = useContext(NomenclatureDataContext);
    if (!context) {
        throw new Error('useNomenclatureData must be used within a NomenclatureDataProvider');
    }
    return context;
};

export const NomenclatureDataProvider = ({ children }) => {
    const { subscribeToUpdates } = useNomenclatures();

    // definitions: { CODE: { id, code, name, kind, display_field, applies_to, sort_order, fields: [...] } }
    const [definitions, setDefinitions] = useState({});
    // entries: { CODE: [ { id, data: {...}, is_active, display_value } ] }
    const [entries, setEntries] = useState({});
    const [isLoading, setIsLoading] = useState(false);
    const [isLoaded, setIsLoaded] = useState(false);
    const [error, setError] = useState(null);

    // Ref to track definitions for SSE handler (avoids stale closure)
    const definitionsRef = useRef({});
    useEffect(() => { definitionsRef.current = definitions; }, [definitions]);

    // Load all nomenclature definitions and their entries
    const loadAll = useCallback(async () => {
        setIsLoading(true);
        setError(null);
        try {
            const res = await api.get('/api/nomenclatures/');
            const data = res.data.results || res.data;
            const noms = Array.isArray(data) ? data : [];

            // Build definitions map keyed by code
            const defsMap = {};
            for (const nom of noms) {
                defsMap[nom.code] = nom;
            }
            setDefinitions(defsMap);
            definitionsRef.current = defsMap;

            // Load entries for all lookup nomenclatures in parallel
            const lookupNoms = noms.filter(n => n.kind === 'lookup');
            const entryResults = await Promise.allSettled(
                lookupNoms.map(nom =>
                    api.get(`/api/nomenclatures/${nom.id}/entries/`).then(res => ({
                        code: nom.code,
                        entries: Array.isArray(res.data) ? res.data : [],
                    }))
                )
            );

            const entriesMap = {};
            for (const result of entryResults) {
                if (result.status === 'fulfilled') {
                    entriesMap[result.value.code] = result.value.entries;
                }
            }
            setEntries(entriesMap);
            setIsLoaded(true);
        } catch (err) {
            setError(err.message || 'Failed to load nomenclature data');
        } finally {
            setIsLoading(false);
        }
    }, []);

    // Load on mount
    useEffect(() => {
        loadAll();
    }, [loadAll]);

    // Subscribe to SSE updates for nomenclature and nomenclature_entry events
    useEffect(() => {
        const unsubscribe = subscribeToUpdates((message) => {
            // Nomenclature definition changed - reload everything
            if (message.object === 'nomenclature') {
                loadAll();
                return;
            }

            if (message.object !== 'nomenclature_entry') return;

            const { operation, data } = message;
            const nomCode = data?.nomenclature_code;
            if (!nomCode) return;

            setEntries(prev => {
                const currentEntries = prev[nomCode] || [];

                if (operation === 'insert') {
                    const exists = currentEntries.some(e => e.id === data.id);
                    if (exists) return prev;
                    return { ...prev, [nomCode]: [...currentEntries, data] };
                }

                if (operation === 'update') {
                    const updated = currentEntries.map(e => e.id === data.id ? { ...e, ...data } : e);
                    return { ...prev, [nomCode]: updated };
                }

                if (operation === 'delete') {
                    return { ...prev, [nomCode]: currentEntries.filter(e => e.id !== data.id) };
                }

                return prev;
            });
        });

        return unsubscribe;
    }, [subscribeToUpdates, loadAll]);

    // Helper: get active entries for a nomenclature code
    const getActiveEntries = useCallback((code) => {
        return (entries[code] || []).filter(e => e.is_active);
    }, [entries]);

    // Helper: get display value for a specific entry
    const getDisplayValue = useCallback((code, entryId) => {
        const entry = (entries[code] || []).find(e => e.id === entryId);
        return entry?.display_value || '';
    }, [entries]);

    // CRUD: create entry
    const createEntry = useCallback(async (nomenclatureId, data) => {
        const res = await api.post(`/api/nomenclatures/${nomenclatureId}/entries/`, { data });
        return res.data;
    }, []);

    // CRUD: update entry
    const updateEntry = useCallback(async (entryId, payload) => {
        const res = await api.patch(`/api/nomenclature-entries/${entryId}/`, payload);
        return res.data;
    }, []);

    // CRUD: delete entry
    const deleteEntry = useCallback(async (entryId) => {
        await api.delete(`/api/nomenclature-entries/${entryId}/`);
    }, []);

    // CRUD: toggle is_active
    const toggleEntryActive = useCallback(async (entryId, currentState) => {
        const res = await api.patch(`/api/nomenclature-entries/${entryId}/`, {
            is_active: !currentState,
        });
        return res.data;
    }, []);

    const value = {
        definitions,
        entries,
        isLoading,
        isLoaded,
        error,
        getActiveEntries,
        getDisplayValue,
        createEntry,
        updateEntry,
        deleteEntry,
        toggleEntryActive,
        refreshAll: loadAll,
    };

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