import React, { createContext, useContext, useState, useCallback, useEffect, useRef, useMemo } from 'react';
import { useAuth } from '../auth/AuthProvider';
import { MANAGEMENT_URL } from '../auth/authConfig';

// ─── Tab / Category Configuration ─────────────────────────────────────────────
export const CATEGORY_TABS = {
    dashboard:  [
        { id: 'overview',    label: 'Overview' },
        { id: 'sessions',    label: 'Sessions' },
    ],
    clients:    [
        { id: 'pending',          label: 'Pending' },
        { id: 'allClients',       label: 'All Clients' },
        { id: 'clientUsers',      label: 'Client Users' },
        { id: 'clientActivity',   label: 'Activity' },
        { id: 'clientDocuments',  label: 'Documents' },
    ],
    campaigns:  [{ id: 'campaigns',  label: 'All Campaigns' }],
    intelligence: [
        { id: 'performance', label: 'Performance' },
        { id: 'insights',    label: 'Insights' },
        { id: 'analysis',    label: 'Analysis' },
    ],
    config:     [
        { id: 'objectives',  label: 'Objective Mapping' },
        { id: 'templates',   label: 'Allocation Templates' },
        { id: 'modifiers',   label: 'Audience Modifiers' },
    ],
    documents:  [{ id: 'documents',      label: 'Documents' }],
};

export const TAB_ENDPOINTS = {
    overview:    '/api/monitoring/health',          // GET
    sessions:    '/api/admin/sessions/list',        // POST {}
    clientUsers: '/api/admin/client-users/list',    // POST {}
    templates:   '/api/admin/templates/list',       // POST {}
    objectives:  '/api/admin/objectives/list',      // POST {}
    campaigns:   '/api/admin/campaigns/list',       // POST {}
    help:        '/api/admin/help/list',            // POST {}
    // documents — self-managing panel, no auto-fetch
};

export const CATEGORY_LABELS = {
    dashboard:    'Dashboard',
    clients:      'Clients',
    campaigns:    'Campaigns',
    intelligence: 'Campaign Intelligence',
    config:       'Configuration',
    documents:    'Documents',
};

// ─── Cache config ─────────────────────────────────────────────────────────────
const CACHE_TTL_MS = 2 * 60 * 1000; // 2 minutes

// ─── Context ──────────────────────────────────────────────────────────────────
const AdminContext = createContext(null);

export function useAdmin() {
    const ctx = useContext(AdminContext);
    if (!ctx) throw new Error('useAdmin must be used within <AdminProvider>');
    return ctx;
}

// ─── Provider ─────────────────────────────────────────────────────────────────
export function AdminProvider({ children }) {
    const {
        sessionUser: user,
        signOut,
        getIdToken,
        isAuthenticated: isSignedIn,
        userRole,
        isAdmin,
        isTech,
        isStaff,
    } = useAuth();

    // Navigation
    const [activeCategory, setActiveCategory] = useState('dashboard');
    const [activeTab,       setActiveTab]      = useState('overview');
    const [collapsed,       setCollapsed]      = useState(false);

    // Active tab fetch state
    const [data,       setData]       = useState(null);
    const [loading,    setLoading]    = useState(false);
    const [error,      setError]      = useState(null);
    const [refreshKey, setRefreshKey] = useState(0);

    // ─── Response cache ───────────────────────────────────────────────────────
    // Stored in a ref so cache reads/writes never trigger re-renders.
    // Shape: Map<url, { data: any, timestamp: number }>
    const cacheRef = useRef(new Map());

    const isCacheValid = (entry) =>
        entry != null && (Date.now() - entry.timestamp) < CACHE_TTL_MS;

    const invalidateCache = useCallback((pathPrefix = null) => {
        if (!pathPrefix) {
            cacheRef.current.clear();
        } else {
            for (const key of cacheRef.current.keys()) {
                if (key.includes(pathPrefix)) cacheRef.current.delete(key);
            }
        }
    }, []);

    // ─── Core API call — JWT Bearer, with GET caching ─────────────────────────
    // Two calling conventions:
    //   apiCall(url, 'POST', body)              — standard
    //   apiCall(url, { method, body, rawResponse }) — options-object for special cases
    //     rawResponse: true  → returns raw fetch Response (for blob downloads)
    //     body: FormData     → multipart upload; Content-Type not set (browser sets boundary)
    const apiCall = useCallback(async (urlOrPath, methodOrOpts = 'GET', body = null) => {
        const url = urlOrPath.startsWith('http') ? urlOrPath : `${MANAGEMENT_URL}${urlOrPath}`;

        // Resolve calling convention
        let method, reqBody, isFormData, rawResponse;
        if (methodOrOpts !== null && typeof methodOrOpts === 'object') {
            method      = methodOrOpts.method || 'GET';
            rawResponse = !!methodOrOpts.rawResponse;
            const b     = methodOrOpts.body ?? null;
            isFormData  = b instanceof FormData;
            reqBody     = isFormData ? b : (typeof b === 'string' ? b : (b ? JSON.stringify(b) : null));
        } else {
            method      = methodOrOpts;
            rawResponse = false;
            isFormData  = false;
            reqBody     = body ? JSON.stringify(body) : null;
        }

        // Cache hit for plain GETs only
        if (method === 'GET' && !rawResponse) {
            const cached = cacheRef.current.get(url);
            if (isCacheValid(cached)) {
                console.debug('[Admin] Cache hit:', urlOrPath);
                return cached.data;
            }
        }

        const token = await getIdToken();
        if (!token) {
            console.warn('[Admin] apiCall: no token');
            return rawResponse ? null : { ok: false, error: 'Not authenticated' };
        }

        const headers = { 'Authorization': `Bearer ${token}` };
        if (!isFormData) headers['Content-Type'] = 'application/json';

        const fetchOpts = { method, headers };
        if (reqBody) fetchOpts.body = reqBody;

        try {
            const res = await fetch(url, fetchOpts);

            if (!res.ok) {
                if (rawResponse) return null;
                const text = await res.text();
                if (res.status !== 404) {
                    console.error(`[Admin] HTTP ${res.status}:`, text.substring(0, 200));
                }
                return { ok: false, error: `HTTP ${res.status}: ${text.substring(0, 100)}` };
            }

            if (rawResponse) return res;

            const result = await res.json();

            if (method === 'GET') {
                cacheRef.current.set(url, { data: result, timestamp: Date.now() });
            } else if (result?.ok) {
                const basePath = urlOrPath.replace(/\/[^/]+$/, '');
                const baseUrl  = `${MANAGEMENT_URL}${basePath}`;
                if (cacheRef.current.has(baseUrl)) {
                    cacheRef.current.set(baseUrl, { data: result, timestamp: Date.now() });
                }
            }

            return result;
        } catch (err) {
            console.error('[Admin] Network error:', err.message);
            return rawResponse ? null : { ok: false, error: 'Network error: ' + err.message };
        }
    }, [getIdToken, invalidateCache]);

    // ─── Navigation ───────────────────────────────────────────────────────────
    const handleSelectCategory = useCallback((categoryId) => {
        setActiveCategory(categoryId);
        const tabs = CATEGORY_TABS[categoryId];
        if (tabs?.length > 0) setActiveTab(tabs[0].id);
        setData(null);
        setError(null);
    }, []);

    const handleSelectTab = useCallback((tabId) => {
        setActiveTab(tabId);
        setData(null);
        setError(null);
    }, []);

    // ─── Tab data fetch ───────────────────────────────────────────────────────
    // /api/monitoring/health is a true GET.
    // All list endpoints use POST with an empty body.
    const fetchTabData = useCallback(async (endpoint) => {
        if (!isSignedIn) return null;
        setLoading(true);
        setError(null);
        try {
            const isGet = endpoint === '/api/monitoring/health';
            const result = isGet
                ? await apiCall(endpoint)
                : await apiCall(endpoint, 'POST', {});
            if (!result?.ok) throw new Error(result?.error || 'Request failed');
            return result;
        } catch (err) {
            console.error('[Admin] Tab fetch error:', err);
            setError(err.message);
            return null;
        } finally {
            setLoading(false);
        }
    }, [isSignedIn, apiCall]);

    // Force-refresh: bust the cache for the current tab endpoint, then re-fetch
    const refresh = useCallback(() => {
        const endpoint = TAB_ENDPOINTS[activeTab];
        if (endpoint) invalidateCache(`${MANAGEMENT_URL}${endpoint}`);
        setRefreshKey(k => k + 1);
    }, [activeTab, invalidateCache]);

    useEffect(() => {
        const endpoint = TAB_ENDPOINTS[activeTab];
        if (!endpoint) {
            setData(null);
            setLoading(false);
            return;
        }
        fetchTabData(endpoint).then(setData);
    }, [activeTab, fetchTabData, refreshKey]);

    // ─── Context value ────────────────────────────────────────────────────────
    const value = useMemo(() => ({
        user, signOut,
        userRole, isAdmin, isTech, isStaff,

        activeCategory, activeTab, collapsed,
        setActiveCategory: handleSelectCategory,
        setActiveTab:      handleSelectTab,
        setCollapsed,
        tabs: CATEGORY_TABS[activeCategory] || [],

        data, loading, error, refresh,
        apiCall,
        invalidateCache,
    }), [
        user, signOut,
        userRole, isAdmin, isTech, isStaff,
        activeCategory, activeTab, collapsed,
        handleSelectCategory, handleSelectTab,
        data, loading, error, refresh,
        apiCall, invalidateCache,
    ]);

    return <AdminContext.Provider value={value}>{children}</AdminContext.Provider>;
}
