import React, { useState, useEffect, useCallback, createContext, useContext } from 'react';
import {
    Box, IconButton, CircularProgress, Collapse, Typography, Tooltip,
    ToggleButtonGroup, ToggleButton,
} from '@mui/material';
import {
    ExpandMore, ChevronRight as ChevronRightIcon,
    Home as HomeIcon,
    CalendarToday, DateRange, Event,
    Schedule as TimetableIcon,
    Class as ClassIcon,
    MenuBook as CurriculumIcon,
    Book as JournalIcon,
    EventNote as PlannerIcon,
    Business as SchoolIcon,
    LinkOff as UnlinkedIcon,
    HourglassEmpty as PendingIcon,
    School as AcademicIcon,
    GridOn as GridIcon,
    Settings as SetupIcon,
    Edit as EditIcon,
    Launch as LaunchIcon,
} from '@mui/icons-material';
import { useNavigate } from 'react-router-dom';
import { useNavigationStore } from '../../../../../../stores/navigationStore';
import { useAuth } from '../../../../../../contexts/AuthContext';
import { NeoGraphNode } from '../../../../../../types/navigation';
import { logger } from '../../../../../../debugConfig';
import { SchoolCalendarWizard, SchoolInfo } from './SchoolCalendarWizard';
import { TeacherTimetableWizard, PeriodTemplate } from './TeacherTimetableWizard';
import { SchoolOnboardingWizard } from './SchoolOnboardingWizard';

type NodeStatus = 'populated' | 'empty' | 'no_school' | 'not_initialized';
type CalendarMode = 'generic' | 'academic';

interface TreeNode extends NeoGraphNode {
    has_children?: boolean;
    children?: TreeNode[];
    is_section?: boolean;
    section_id?: string;
    status?: NodeStatus;
    neo4j_props?: Record<string, string>;
}

interface SchoolStatus {
    status: string;
    user_role?: string;
    school_id?: string;
    school_has_calendar?: boolean;
    teacher_has_timetable?: boolean;
    timetable_id?: string | null;
    periods_template?: PeriodTemplate[] | null;
    school_info?: SchoolInfo;
}

const NODE_ICONS: Record<string, React.ElementType> = {
    User: HomeIcon,
    CalendarYear: CalendarToday,
    CalendarMonth: DateRange,
    CalendarWeek: DateRange,
    CalendarDay: Event,
    AcademicYear: AcademicIcon,
    AcademicTerm: AcademicIcon,
    AcademicWeek: DateRange,
    TeacherTimetable: TimetableIcon,
    SubjectClass: ClassIcon,
    TimetableLesson: TimetableIcon,
    TimetableSlot: GridIcon,
    Journal: JournalIcon,
    Planner: PlannerIcon,
    School: SchoolIcon,
    Department: SchoolIcon,
    Section: HomeIcon,
};

const SECTION_ICONS: Record<string, React.ElementType> = {
    calendar: CalendarToday,
    timetable: TimetableIcon,
    classes: ClassIcon,
    curriculum: CurriculumIcon,
    journal: JournalIcon,
    planner: PlannerIcon,
    school: SchoolIcon,
};

const STATUS_MESSAGES: Record<NodeStatus, string> = {
    populated: '',
    empty: 'Not set up yet',
    no_school: 'Join a school to unlock',
    not_initialized: 'Setting up...',
};

// ─── Panel context ─────────────────────────────────────────────────────────────

interface NavPanelContextValue {
    calendarMode: CalendarMode;
    setCalendarMode: (m: CalendarMode) => void;
    academicCalendarStatus: 'idle' | 'loading' | 'populated' | 'empty' | 'no_school' | 'error';
    academicTerms: TreeNode[];
    schoolStatus: SchoolStatus | null;
    onSetupSchoolCalendar: () => void;
    onSetupTimetable: () => void;
    onOnboardSchool: () => void;
    activeNodeId?: string;
    timetableView: 'class' | 'term';
    setTimetableView: (v: 'class' | 'term') => void;
    timetableTermNodes: TreeNode[];
    timetableTermStatus: 'idle' | 'loading' | 'populated' | 'empty';
}

const NavPanelContext = createContext<NavPanelContextValue>({
    calendarMode: 'generic',
    setCalendarMode: () => {},
    academicCalendarStatus: 'idle',
    academicTerms: [],
    schoolStatus: null,
    onSetupSchoolCalendar: () => {},
    onSetupTimetable: () => {},
    onOnboardSchool: () => {},
    timetableView: 'class',
    setTimetableView: () => {},
    timetableTermNodes: [],
    timetableTermStatus: 'idle',
});

// ─── TreeItem ─────────────────────────────────────────────────────────────────

interface TreeItemProps {
    node: TreeNode;
    depth: number;
    onSelect: (node: TreeNode) => void;
    onExpand: (node: TreeNode) => Promise<TreeNode[]>;
}

function TreeItem({ node, depth, onSelect, onExpand }: TreeItemProps) {
    const ctx = useContext(NavPanelContext);
    const navigate = useNavigate();
    const [expanded, setExpanded] = useState(node.is_section && node.status === 'populated');
    const [children, setChildren] = useState<TreeNode[]>(node.children || []);
    const [loading, setLoading] = useState(false);

    const isSection = !!node.is_section;
    const isCalendarSection = isSection && node.section_id === 'calendar';
    const isTimetableSection = isSection && node.section_id === 'timetable';
    const isSchoolSection = isSection && node.section_id === 'school';
    const isClassesSection = isSection && node.section_id === 'classes';
    const SectionIcon = node.section_id ? SECTION_ICONS[node.section_id] : null;
    const Icon = SectionIcon || NODE_ICONS[node.node_type] || HomeIcon;

    const canExpand = node.has_children !== false
        && node.node_type !== 'CalendarDay'
        && node.status !== 'empty'
        && node.status !== 'no_school'
        && node.status !== 'not_initialized';

    const isActive = !isSection && node.neo4j_node_id === ctx.activeNodeId;
    const isEmpty = node.status === 'empty' || node.status === 'no_school' || node.status === 'not_initialized';

    const displayChildren = isCalendarSection && ctx.calendarMode === 'academic'
        ? ctx.academicTerms
        : isTimetableSection && ctx.timetableView === 'term'
            ? ctx.timetableTermNodes
            : children;

    const academicEmpty = isCalendarSection
        && ctx.calendarMode === 'academic'
        && (ctx.academicCalendarStatus === 'empty' || ctx.academicCalendarStatus === 'idle');

    const handleToggle = async (e: React.MouseEvent) => {
        e.stopPropagation();
        if (!expanded && displayChildren.length === 0 && canExpand && !isCalendarSection) {
            setLoading(true);
            try {
                const loaded = await onExpand(node);
                setChildren(loaded);
            } finally {
                setLoading(false);
            }
        }
        setExpanded(v => !v);
    };

    const handleClick = () => {
        if (!isSection) {
            onSelect(node);
        } else {
            // Sections with a real node ID (e.g. the school section) navigate AND expand
            if (node.neo4j_node_id) onSelect(node);
            if (canExpand || (isCalendarSection && ctx.calendarMode === 'academic')) {
                handleToggle({ stopPropagation: () => {} } as React.MouseEvent);
            }
        }
    };

    // Derive action buttons per section
    const ss = ctx.schoolStatus;
    // School section: calendar setup (admin) or pending notice (non-admin)
    const showCalendarSetup = isSchoolSection
        && ss && ss.status !== 'no_school'
        && !ss.school_has_calendar && ss.user_role === 'school_admin';
    const showCalendarPending = isSchoolSection
        && ss && ss.status !== 'no_school'
        && !ss.school_has_calendar && ss.user_role !== 'school_admin';
    // School section: onboarding prompt when no school linked
    const showOnboard = isSchoolSection && (!ss || ss.status === 'no_school');
    // Timetable section: teacher timetable setup (requires school calendar first)
    const showTimetableSetup = isTimetableSection && node.status === 'empty'
        && ss && ss.status !== 'no_school'
        && ss.school_has_calendar && !ss.teacher_has_timetable;
    const showLegacySetup = isTimetableSection && node.status === 'empty' && !ss;
    const showTimetableEdit = isTimetableSection && node.status === 'populated'
        && ss && ss.status !== 'no_school' && !!ss.teacher_has_timetable;
    const showTimetableView = isTimetableSection && node.status === 'populated';
    const showClassesView = isClassesSection && node.status === 'populated';

    if (isSection) {
        return (
            <Box>
                <Box
                    onClick={handleClick}
                    sx={{
                        display: 'flex', alignItems: 'center',
                        px: 1, py: 0.6,
                        cursor: (canExpand || isCalendarSection) ? 'pointer' : 'default',
                        mt: depth === 0 ? 0.5 : 0,
                        borderRadius: 1,
                        '&:hover': (canExpand || isCalendarSection) ? { bgcolor: 'action.hover' } : {},
                    }}
                >
                    <Box sx={{ width: 18, flexShrink: 0, display: 'flex', alignItems: 'center' }}>
                        {(canExpand || (isCalendarSection && !academicEmpty)) && (
                            loading
                                ? <CircularProgress size={10} />
                                : (
                                    <IconButton size="small" sx={{ p: 0, color: 'text.secondary' }} onClick={handleToggle}>
                                        {expanded
                                            ? <ExpandMore sx={{ fontSize: 14 }} />
                                            : <ChevronRightIcon sx={{ fontSize: 14 }} />}
                                    </IconButton>
                                )
                        )}
                        {isEmpty && !isCalendarSection && !isTimetableSection && !isSchoolSection && !isClassesSection && (
                            <Box sx={{ width: 18, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                                {node.status === 'no_school'
                                    ? <UnlinkedIcon sx={{ fontSize: 11, color: 'text.disabled' }} />
                                    : node.status === 'not_initialized'
                                        ? <PendingIcon sx={{ fontSize: 11, color: 'text.disabled' }} />
                                        : null}
                            </Box>
                        )}
                    </Box>

                    <Icon sx={{ fontSize: 13, mr: 0.75, flexShrink: 0, color: isEmpty ? 'text.disabled' : 'primary.main', opacity: isEmpty ? 0.5 : 1 }} />

                    <Typography
                        variant="caption"
                        sx={{
                            fontWeight: 600, letterSpacing: '0.04em',
                            textTransform: 'uppercase', fontSize: '0.68rem',
                            color: isEmpty ? 'text.disabled' : 'text.secondary',
                            flexGrow: 1, overflow: 'hidden',
                            textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                        }}
                    >
                        {node.label}
                    </Typography>

                    {isEmpty && !isCalendarSection && !isTimetableSection && !isSchoolSection && !isClassesSection && node.status && (
                        <Tooltip title={STATUS_MESSAGES[node.status]} placement="right">
                            <Typography variant="caption" sx={{ fontSize: '0.6rem', color: 'text.disabled', ml: 0.5, flexShrink: 0 }}>
                                {node.status === 'no_school' ? '—' : '…'}
                            </Typography>
                        </Tooltip>
                    )}

                    {/* School section — onboarding when no school */}
                    {showOnboard && (
                        <Tooltip title="Find and join your school" placement="right">
                            <IconButton
                                size="small"
                                sx={{ p: 0.25, ml: 0.5, color: 'primary.main' }}
                                onClick={e => { e.stopPropagation(); ctx.onOnboardSchool(); }}
                            >
                                <SetupIcon sx={{ fontSize: 13 }} />
                            </IconButton>
                        </Tooltip>
                    )}
                    {/* Calendar section — role-aware action */}
                    {showCalendarSetup && (
                        <Tooltip title="Set up school calendar" placement="right">
                            <IconButton
                                size="small"
                                sx={{ p: 0.25, ml: 0.5, color: 'primary.main' }}
                                onClick={e => { e.stopPropagation(); ctx.onSetupSchoolCalendar(); }}
                            >
                                <SetupIcon sx={{ fontSize: 13 }} />
                            </IconButton>
                        </Tooltip>
                    )}
                    {showCalendarPending && (
                        <Tooltip title="School calendar not set up yet — contact your school admin" placement="right">
                            <PendingIcon sx={{ fontSize: 11, color: 'text.disabled', ml: 0.5 }} />
                        </Tooltip>
                    )}
                    {showTimetableSetup && (
                        <Tooltip title="Set up my timetable" placement="right">
                            <IconButton
                                size="small"
                                sx={{ p: 0.25, ml: 0.5, color: 'primary.main' }}
                                onClick={e => { e.stopPropagation(); ctx.onSetupTimetable(); }}
                            >
                                <SetupIcon sx={{ fontSize: 13 }} />
                            </IconButton>
                        </Tooltip>
                    )}
                    {showLegacySetup && (
                        <Tooltip title="Set up timetable" placement="right">
                            <IconButton
                                size="small"
                                sx={{ p: 0.25, ml: 0.5, color: 'primary.main' }}
                                onClick={e => { e.stopPropagation(); ctx.onSetupTimetable(); }}
                            >
                                <SetupIcon sx={{ fontSize: 13 }} />
                            </IconButton>
                        </Tooltip>
                    )}
                    {showTimetableEdit && (
                        <Tooltip title="Edit my class schedule" placement="right">
                            <IconButton
                                size="small"
                                sx={{ p: 0.25, ml: 0.5, color: 'text.secondary' }}
                                onClick={e => { e.stopPropagation(); ctx.onSetupTimetable(); }}
                            >
                                <EditIcon sx={{ fontSize: 13 }} />
                            </IconButton>
                        </Tooltip>
                    )}
                    {showTimetableView && (
                        <Tooltip title="View as lesson list" placement="right">
                            <IconButton
                                size="small"
                                sx={{ p: 0.25, ml: 0.5, color: 'text.secondary' }}
                                onClick={e => { e.stopPropagation(); navigate('/my-lessons'); }}
                            >
                                <LaunchIcon sx={{ fontSize: 13 }} />
                            </IconButton>
                        </Tooltip>
                    )}
                    {showClassesView && (
                        <Tooltip title="View my classes" placement="right">
                            <IconButton
                                size="small"
                                sx={{ p: 0.25, ml: 0.5, color: 'text.secondary' }}
                                onClick={e => { e.stopPropagation(); navigate('/my-classes'); }}
                            >
                                <LaunchIcon sx={{ fontSize: 13 }} />
                            </IconButton>
                        </Tooltip>
                    )}
                </Box>

                {/* Timetable view toggle */}
                {isTimetableSection && node.status === 'populated' && (
                    <Box sx={{ px: 1.5, pb: 0.5 }}>
                        <ToggleButtonGroup
                            value={ctx.timetableView}
                            exclusive
                            onChange={(_, v) => { if (v) ctx.setTimetableView(v); }}
                            size="small"
                            sx={{ height: 22 }}
                        >
                            <ToggleButton value="class" sx={{ px: 1, fontSize: '0.6rem', textTransform: 'none' }}>
                                By Class
                            </ToggleButton>
                            <ToggleButton value="term" sx={{ px: 1, fontSize: '0.6rem', textTransform: 'none' }}>
                                By Term
                            </ToggleButton>
                        </ToggleButtonGroup>
                        {ctx.timetableView === 'term' && ctx.timetableTermStatus === 'loading' && (
                            <CircularProgress size={10} sx={{ mt: 0.5, ml: 0.5 }} />
                        )}
                        {ctx.timetableView === 'term' && ctx.timetableTermStatus === 'empty' && (
                            <Typography variant="caption" sx={{ display: 'block', color: 'text.disabled', fontSize: '0.6rem', mt: 0.5 }}>
                                No academic calendar linked to timetable
                            </Typography>
                        )}
                    </Box>
                )}

                {/* Calendar mode toggle */}
                {isCalendarSection && (
                    <Box sx={{ px: 1.5, pb: 0.5 }}>
                        <ToggleButtonGroup
                            value={ctx.calendarMode}
                            exclusive
                            onChange={(_, v) => { if (v) ctx.setCalendarMode(v); }}
                            size="small"
                            sx={{ height: 22 }}
                        >
                            <ToggleButton value="generic" sx={{ px: 1, fontSize: '0.6rem', textTransform: 'none' }}>
                                Generic
                            </ToggleButton>
                            <ToggleButton value="academic" sx={{ px: 1, fontSize: '0.6rem', textTransform: 'none' }}>
                                Academic
                            </ToggleButton>
                        </ToggleButtonGroup>
                        {ctx.calendarMode === 'academic' && academicEmpty && (
                            <Typography variant="caption" sx={{ display: 'block', color: 'text.disabled', fontSize: '0.6rem', mt: 0.5 }}>
                                No academic calendar — set up school calendar first
                            </Typography>
                        )}
                        {ctx.calendarMode === 'academic' && ctx.academicCalendarStatus === 'loading' && (
                            <CircularProgress size={10} sx={{ mt: 0.5, ml: 0.5 }} />
                        )}
                    </Box>
                )}

                {(canExpand
                    || (isCalendarSection && ctx.calendarMode === 'academic' && displayChildren.length > 0)
                    || (isTimetableSection && ctx.timetableView === 'term' && displayChildren.length > 0)
) && (
                    <Collapse in={expanded} timeout="auto">
                        {displayChildren.map(child => (
                            <TreeItem key={child.neo4j_node_id} node={child} depth={depth + 1}
                                onSelect={onSelect} onExpand={onExpand} />
                        ))}
                    </Collapse>
                )}
            </Box>
        );
    }

    // Regular navigable node
    return (
        <Box>
            <Box
                onClick={handleClick}
                sx={{
                    display: 'flex', alignItems: 'center',
                    pl: depth * 1.5 + 0.5, pr: 0.5, py: 0.35,
                    cursor: 'pointer', borderRadius: 1, mx: 0.5,
                    fontSize: '0.78rem', minHeight: 26,
                    bgcolor: isActive ? 'action.selected' : 'transparent',
                    '&:hover': { bgcolor: isActive ? 'action.selected' : 'action.hover' },
                }}
            >
                <Box sx={{ width: 18, flexShrink: 0, display: 'flex', alignItems: 'center' }}>
                    {canExpand && (
                        loading
                            ? <CircularProgress size={10} />
                            : (
                                <IconButton size="small" sx={{ p: 0, color: 'text.secondary' }} onClick={handleToggle}>
                                    {expanded
                                        ? <ExpandMore sx={{ fontSize: 14 }} />
                                        : <ChevronRightIcon sx={{ fontSize: 14 }} />}
                                </IconButton>
                            )
                    )}
                </Box>
                <Icon sx={{ fontSize: 13, mr: 0.75, flexShrink: 0, color: isActive ? 'primary.main' : 'text.secondary' }} />
                <Box sx={{
                    overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                    flexGrow: 1, fontSize: '0.78rem',
                    color: isActive ? 'primary.main' : 'text.primary',
                    fontWeight: isActive ? 600 : 400,
                }}>
                    {node.label}
                </Box>
            </Box>

            {canExpand && (
                <Collapse in={expanded} timeout="auto">
                    {children.map(child => (
                        <TreeItem key={child.neo4j_node_id} node={child} depth={depth + 1}
                            onSelect={onSelect} onExpand={onExpand} />
                    ))}
                </Collapse>
            )}
        </Box>
    );
}

// ─── Main Panel ───────────────────────────────────────────────────────────────

export function CCGraphNavPanel() {
    const { accessToken } = useAuth();
    const navigate = useNavigate();
    const { navigateToNeoNode, context } = useNavigationStore();
    const [tree, setTree] = useState<TreeNode | null>(null);
    const [schoolStatus, setSchoolStatus] = useState<SchoolStatus | null>(null);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState<string | null>(null);

    const [calendarMode, setCalendarMode] = useState<CalendarMode>('generic');
    const [academicCalendarStatus, setAcademicCalendarStatus] = useState<NavPanelContextValue['academicCalendarStatus']>('idle');
    const [academicTerms, setAcademicTerms] = useState<TreeNode[]>([]);
    const [timetableView, setTimetableView] = useState<'class' | 'term'>('class');
    const [timetableTermNodes, setTimetableTermNodes] = useState<TreeNode[]>([]);
    const [timetableTermStatus, setTimetableTermStatus] = useState<'idle' | 'loading' | 'populated' | 'empty'>('idle');
    const [timetableNodeId, setTimetableNodeId] = useState<string | undefined>();
    const [timetableDb, setTimetableDb] = useState<string | undefined>();

    const [calendarWizardOpen, setCalendarWizardOpen] = useState(false);
    const [timetableWizardOpen, setTimetableWizardOpen] = useState(false);
    const [onboardingWizardOpen, setOnboardingWizardOpen] = useState(false);

    const apiBase = import.meta.env.VITE_API_BASE as string;
    const activeNodeId = context.node?.type !== 'workspace' ? context.node?.id : undefined;

    const fetchTree = useCallback(async () => {
        if (!accessToken) return;
        setLoading(true);
        setError(null);
        try {
            const res = await fetch(`${apiBase}/graph/tree`, {
                headers: { Authorization: `Bearer ${accessToken}` },
            });
            if (!res.ok) throw new Error(`${res.status}`);
            const data = await res.json();
            setTree(data.tree);
        } catch (err) {
            logger.error('graph-nav-panel', 'Failed to load graph tree', err);
            setError('Failed to load navigation tree');
        } finally {
            setLoading(false);
        }
    }, [accessToken, apiBase]);

    const fetchSchoolStatus = useCallback(async () => {
        if (!accessToken) return;
        try {
            const res = await fetch(`${apiBase}/school/status`, {
                headers: { Authorization: `Bearer ${accessToken}` },
            });
            if (!res.ok) return;
            const data = await res.json();
            setSchoolStatus(data);
        } catch {
            // non-fatal — panel still works without school status
        }
    }, [accessToken, apiBase]);

    useEffect(() => {
        if (accessToken && !tree) fetchTree();
    }, [accessToken, tree, fetchTree]);

    useEffect(() => {
        if (!tree) return;
        const ttSection = tree.children?.find(n => n.section_id === 'timetable');
        if (ttSection && ttSection.node_type === 'TeacherTimetable') {
            setTimetableNodeId(ttSection.neo4j_node_id);
            setTimetableDb(ttSection.neo4j_db_name);
        }
    }, [tree]);

    useEffect(() => {
        if (accessToken && !schoolStatus) fetchSchoolStatus();
    }, [accessToken, schoolStatus, fetchSchoolStatus]);

    // Fetch timetable term nodes when switching to term view
    useEffect(() => {
        if (timetableView !== 'term' || !timetableNodeId || !timetableDb || !accessToken) return;
        if (timetableTermStatus !== 'idle') return;
        setTimetableTermStatus('loading');
        const params = new URLSearchParams({
            neo4j_node_id: timetableNodeId,
            neo4j_db_name: timetableDb,
            node_type: 'TeacherTimetable',
            section_id: 'timetable-term',
        });
        fetch(`${apiBase}/graph/node/children?${params}`, {
            headers: { Authorization: `Bearer ${accessToken}` },
        })
            .then(r => r.json())
            .then(data => {
                setTimetableTermNodes(data.children || []);
                setTimetableTermStatus(data.children?.length > 0 ? 'populated' : 'empty');
            })
            .catch(() => setTimetableTermStatus('empty'));
    }, [timetableView, timetableNodeId, timetableDb, accessToken, apiBase, timetableTermStatus]);

    // Fetch academic calendar when switching to academic mode
    useEffect(() => {
        if (calendarMode !== 'academic' || !accessToken) return;
        if (academicCalendarStatus !== 'idle') return;
        setAcademicCalendarStatus('loading');
        fetch(`${apiBase}/graph/calendar/academic`, {
            headers: { Authorization: `Bearer ${accessToken}` },
        })
            .then(r => r.json())
            .then(data => {
                if (data.status === 'populated') {
                    setAcademicTerms(data.terms);
                    setAcademicCalendarStatus('populated');
                } else {
                    setAcademicCalendarStatus(data.status || 'empty');
                }
            })
            .catch(() => setAcademicCalendarStatus('error'));
    }, [calendarMode, accessToken, apiBase, academicCalendarStatus]);

    const handleSetCalendarMode = useCallback((m: CalendarMode) => {
        setCalendarMode(m);
        if (m === 'academic') setAcademicCalendarStatus('idle');
    }, []);

    const handleExpand = useCallback(async (node: TreeNode): Promise<TreeNode[]> => {
        if (!accessToken) return [];
        const params = new URLSearchParams({
            neo4j_node_id: node.neo4j_node_id,
            neo4j_db_name: node.neo4j_db_name,
            node_type: node.node_type,
            section_id: node.section_id || '',
        });
        try {
            const res = await fetch(`${apiBase}/graph/node/children?${params}`, {
                headers: { Authorization: `Bearer ${accessToken}` },
            });
            if (!res.ok) return [];
            const data = await res.json();
            return data.children || [];
        } catch {
            return [];
        }
    }, [accessToken, apiBase]);

    const handleSelect = useCallback((node: TreeNode) => {
        // Section nodes with artificial IDs (node_type="Section") have no canvas shape util
        if (node.is_section && node.node_type === "Section") return;
        // SubjectClass nodes don't yet exist in Neo4j — navigate to class detail page
        if (node.node_type === "SubjectClass") {
            navigate(`/classes/${node.neo4j_node_id}`);
            return;
        }
        navigateToNeoNode(node);
    }, [navigateToNeoNode, navigate]);

    const refreshAll = useCallback(() => {
        setTree(null);
        setSchoolStatus(null);
        setAcademicCalendarStatus('idle');
        setAcademicTerms([]);
    }, []);

    const handleCalendarWizardComplete = useCallback(() => {
        logger.info('graph-nav-panel', 'School calendar setup complete');
        refreshAll();
    }, [refreshAll]);

    const handleTimetableWizardComplete = useCallback((timetableId: string) => {
        logger.info('graph-nav-panel', 'Teacher timetable setup complete', { timetableId });
        refreshAll();
    }, [refreshAll]);

    if (loading) {
        return (
            <Box sx={{ display: 'flex', justifyContent: 'center', pt: 3 }}>
                <CircularProgress size={20} />
            </Box>
        );
    }

    if (error) {
        return (
            <Box sx={{ p: 1.5, fontSize: '0.78rem', color: 'error.main' }}>
                {error}
            </Box>
        );
    }

    if (!tree) return null;

    const ctxValue: NavPanelContextValue = {
        calendarMode,
        setCalendarMode: handleSetCalendarMode,
        academicCalendarStatus,
        academicTerms,
        schoolStatus,
        onSetupSchoolCalendar: () => setCalendarWizardOpen(true),
        onSetupTimetable: () => setTimetableWizardOpen(true),
        onOnboardSchool: () => setOnboardingWizardOpen(true),
        activeNodeId,
        timetableView,
        setTimetableView: (v) => { setTimetableView(v); if (v === 'class') { setTimetableTermStatus('idle'); setTimetableTermNodes([]); } },
        timetableTermNodes,
        timetableTermStatus,
    };

    const defaultSchoolInfo: SchoolInfo = {
        name: '', urn: '', website: '', address: {},
        headteacher: '', term_dates_url: '', staff_list_url: '',
    };

    return (
        <NavPanelContext.Provider value={ctxValue}>
            <Box sx={{ pt: 0.5, pb: 2 }}>
                <TreeItem
                    node={tree}
                    depth={0}
                    onSelect={handleSelect}
                    onExpand={handleExpand}
                />
            </Box>

            {schoolStatus?.school_info && (
                <SchoolCalendarWizard
                    open={calendarWizardOpen}
                    onClose={() => setCalendarWizardOpen(false)}
                    onComplete={handleCalendarWizardComplete}
                    apiBase={apiBase}
                    schoolInfo={schoolStatus.school_info || defaultSchoolInfo}
                />
            )}

            <TeacherTimetableWizard
                open={timetableWizardOpen}
                onClose={() => setTimetableWizardOpen(false)}
                onComplete={handleTimetableWizardComplete}
                apiBase={apiBase}
                periodsTemplate={schoolStatus?.periods_template || []}
                timetableId={schoolStatus?.timetable_id || null}
            />

            <SchoolOnboardingWizard
                open={onboardingWizardOpen}
                onClose={() => setOnboardingWizardOpen(false)}
                onComplete={() => {
                    setOnboardingWizardOpen(false);
                    // Reload tree + school status after successful onboarding
                    setTree(null);
                    setSchoolStatus(null);
                }}
                apiBase={apiBase}
            />
        </NavPanelContext.Provider>
    );
}
