import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { useAuth } from './AuthContext';
import { useUser } from './UserContext';
import { logger } from '../debugConfig';
import { CCUserNodeProps, CCCalendarNodeProps, CCUserTeacherTimetableNodeProps } from '../utils/tldraw/cc-base/cc-graph/cc-graph-types';
import { CalendarStructure, WorkerStructure } from '../types/navigation';
import { useNavigationStore } from '../stores/navigationStore';

// Core Node Types
export interface CalendarNode {
  id: string;
  label: string;
  title: string;
  node_storage_path: string;
  type?: CCCalendarNodeProps['__primarylabel__'];
  nodeData?: CCCalendarNodeProps;
}

export interface WorkerNode {
  id: string;
  label: string;
  title: string;
  node_storage_path: string;
  type?: CCUserTeacherTimetableNodeProps['__primarylabel__'];
  nodeData?: CCUserTeacherTimetableNodeProps;
}

// Calendar Structure Types
export interface CalendarDay {
  id: string;
  date: string;
  title: string;
}

export interface CalendarWeek {
  id: string;
  title: string;
  days: { id: string }[];
  startDate: string;
  endDate: string;
}

export interface CalendarMonth {
  id: string;
  title: string;
  days: { id: string }[];
  weeks: { id: string }[];
  year: string;
  month: string;
}

export interface CalendarYear {
  id: string;
  title: string;
  months: { id: string }[];
  year: string;
}

// Worker Structure Types
export interface TimetableEntry {
  id: string;
  title: string;
  type: string;
  startTime: string;
  endTime: string;
}

export interface ClassEntry {
  id: string;
  title: string;
  type: string;
}

export interface LessonEntry {
  id: string;
  title: string;
  type: string;
}

interface NeoUserContextType {
  userNode: CCUserNodeProps | null;
  calendarNode: CalendarNode | null;
  workerNode: WorkerNode | null;
  userDbName: string | null;
  workerDbName: string | null;
  isLoading: boolean;
  isInitialized: boolean;
  error: string | null;
  
  // Calendar Navigation
  navigateToDay: (id: string) => Promise<void>;
  navigateToWeek: (id: string) => Promise<void>;
  navigateToMonth: (id: string) => Promise<void>;
  navigateToYear: (id: string) => Promise<void>;
  currentCalendarNode: CalendarNode | null;
  calendarStructure: CalendarStructure | null;
  
  // Worker Navigation
  navigateToTimetable: (id: string) => Promise<void>;
  navigateToJournal: (id: string) => Promise<void>;
  navigateToPlanner: (id: string) => Promise<void>;
  navigateToClass: (id: string) => Promise<void>;
  navigateToLesson: (id: string) => Promise<void>;
  currentWorkerNode: WorkerNode | null;
  workerStructure: WorkerStructure | null;
}

const NeoUserContext = createContext<NeoUserContextType>({
  userNode: null,
  calendarNode: null,
  workerNode: null,
  userDbName: null,
  workerDbName: null,
  isLoading: false,
  isInitialized: false,
  error: null,
  navigateToDay: async () => {},
  navigateToWeek: async () => {},
  navigateToMonth: async () => {},
  navigateToYear: async () => {},
  navigateToTimetable: async () => {},
  navigateToJournal: async () => {},
  navigateToPlanner: async () => {},
  navigateToClass: async () => {},
  navigateToLesson: async () => {},
  currentCalendarNode: null,
  currentWorkerNode: null,
  calendarStructure: null,
  workerStructure: null
});

export const NeoUserProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const { user, accessToken } = useAuth();
  const { profile, isInitialized: isUserInitialized } = useUser();
  const navigationStore = useNavigationStore();
  
  const [userNode, setUserNode] = useState<CCUserNodeProps | null>(null);
  const [calendarNode] = useState<CalendarNode | null>(null);
  const [workerNode] = useState<WorkerNode | null>(null);
  const [currentCalendarNode, setCurrentCalendarNode] = useState<CalendarNode | null>(null);
  const [currentWorkerNode, setCurrentWorkerNode] = useState<WorkerNode | null>(null);
  const [calendarStructure] = useState<CalendarStructure | null>(null);
  const [workerStructure] = useState<WorkerStructure | null>(null);
  const [userDbName, setUserDbName] = useState<string | null>(null);
  const [workerDbName, setWorkerDbName] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isInitialized, setIsInitialized] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Use ref for initialization tracking to prevent re-renders
  const initializationRef = React.useRef({
    hasStarted: false,
    isComplete: false
  });

  // Add base properties for node data
  const getBaseNodeProps = () => ({
    title: '',
    w: 200,
    h: 200,
    headerColor: '#000000',
    backgroundColor: '#ffffff',
    isLocked: false,
    __primarylabel__: 'UserTeacherTimetable',
    uuid_string: '',
    node_storage_path: '',
    created: new Date().toISOString(),
    merged: new Date().toISOString(),
    state: {
      parentId: null,
      isPageChild: false,
      hasChildren: false,
      bindings: [],
    },
    defaultComponent: true,
  });

  // Initialize context when dependencies are ready
  useEffect(() => {
    logger.debug('neo-user-context', '🔄 useEffect triggered', {
      isUserInitialized,
      hasProfile: !!profile,
      hasUser: !!user,
      isInitialized,
      hasStarted: initializationRef.current.hasStarted
    });
    
    if (!isUserInitialized) {
      logger.debug('neo-user-context', '⏳ Waiting for user context initialization');
      return;
    }

    if (!profile) {
      if (!initializationRef.current.isComplete) {
        setIsLoading(false);
        setIsInitialized(true);
        initializationRef.current.isComplete = true;
        logger.debug('neo-user-context', 'ℹ️ No profile available; marking context initialized');
      }
      return;
    }

    if (isInitialized || initializationRef.current.hasStarted) {
      logger.debug('neo-user-context', 'ℹ️ Initialization already in progress or complete', {
        isInitialized,
        hasStarted: initializationRef.current.hasStarted
      });
      return;
    }

    const initializeContext = async () => {
      try {
        initializationRef.current.hasStarted = true;
        setIsLoading(true);
        setError(null);

        // Inject auth into navigation store so Supabase queries work
        if (user?.id && accessToken) {
          navigationStore.setAuthInfo(accessToken, user.id);
        }

        // Initialize user node in profile context
        logger.debug('neo-user-context', '🔄 Starting context initialization');

        // Initialize user node — race against 8s timeout so spinner never hangs
        const switchTimeout = new Promise<void>((_, reject) =>
          setTimeout(() => reject(new Error('switchContext timed out after 8000ms')), 8000)
        )
        try {
          await Promise.race([
            navigationStore.switchContext({
              main: 'profile',
              base: 'profile',
              extended: 'overview'
            }, null, null),
            switchTimeout
          ]);

          const userNavigationNode = navigationStore.context.node;
          if (userNavigationNode?.id && userNavigationNode?.data) {
            const userNodeData: CCUserNodeProps = {
              ...getBaseNodeProps(),
              __primarylabel__: 'User',
              uuid_string: userNavigationNode.id,
              node_storage_path: userNavigationNode.node_storage_path || '',
              title: String(userNavigationNode.data?.user_name || 'User'),
              user_name: String(userNavigationNode.data?.user_name || 'User'),
              user_email: user?.email || '',
              user_type: 'User',
              user_id: userNavigationNode.id,
              worker_node_data: JSON.stringify(userNavigationNode.data || {})
            };
            setUserNode(userNodeData);
            logger.debug('neo-user-context', '✅ User node loaded from navigation store');
          } else if (userNavigationNode?.id) {
            logger.debug('neo-user-context', 'ℹ️ User node exists but data not yet loaded - will retry later', {
              nodeId: userNavigationNode.id,
              hasData: !!userNavigationNode.data
            });
          } else {
            logger.debug('neo-user-context', 'ℹ️ No user node in navigation store yet - will retry later');
          }
        } catch (navError) {
          logger.warn('neo-user-context', '⚠️ Navigation store initialization failed - continuing without user node', {
            error: navError instanceof Error ? navError.message : String(navError)
          });
          // Continue without user node - this is not critical for basic functionality
        }

        // Set final state — userDbName signals auth availability for UI guards
        setUserDbName(user?.id || null);
        setWorkerDbName(null);
        setIsInitialized(true);
        setIsLoading(false);
        initializationRef.current.isComplete = true;

        logger.debug('neo-user-context', '✅ Context initialization complete');
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : 'Failed to initialize user context';
        logger.error('neo-user-context', '❌ Failed to initialize context', { error: errorMessage });
        setError(errorMessage);
        setIsLoading(false);
        setIsInitialized(true);
        initializationRef.current.isComplete = true;
      }
    };

    initializeContext();
  }, [user, profile, isUserInitialized, navigationStore, isInitialized]);

  // Calendar Navigation Functions
  const navigateToDay = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'calendar',
        extended: 'day'
      }, null, null);

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCCalendarNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'CalendarDay',
          uuid_string: id || node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          name: node.label,
          calendar_type: 'day',
          calendar_name: node.label,
          start_date: new Date().toISOString(),
          end_date: new Date().toISOString()
        };

        setCurrentCalendarNode({
          id: id || node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'CalendarDay',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to day');
    } finally {
      setIsLoading(false);
    }
  };

  const navigateToWeek = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'calendar',
        extended: 'week'
      }, null, null);

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCCalendarNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'CalendarWeek',
          uuid_string: id || node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          name: node.label,
          calendar_type: 'week',
          calendar_name: node.label,
          start_date: new Date().toISOString(),
          end_date: new Date().toISOString()
        };

        setCurrentCalendarNode({
          id: id || node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'CalendarWeek',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to week');
    } finally {
      setIsLoading(false);
    }
  };

  const navigateToMonth = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'calendar',
        extended: 'month'
      }, null, null);

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCCalendarNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'CalendarMonth',
          uuid_string: id || node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          name: node.label,
          calendar_type: 'month',
          calendar_name: node.label,
          start_date: new Date().toISOString(),
          end_date: new Date().toISOString()
        };

        setCurrentCalendarNode({
          id: id || node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'CalendarMonth',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to month');
    } finally {
      setIsLoading(false);
    }
  };

  const navigateToYear = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'calendar',
        extended: 'year'
      }, null, null);

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCCalendarNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'CalendarYear',
          uuid_string: id || node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          name: node.label,
          calendar_type: 'year',
          calendar_name: node.label,
          start_date: new Date().toISOString(),
          end_date: new Date().toISOString()
        };

        setCurrentCalendarNode({
          id: id || node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'CalendarYear',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to year');
    } finally {
      setIsLoading(false);
    }
  };

  // Worker Navigation Functions
  const navigateToTimetable = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'teaching',
        extended: 'timetable'
      }, null, null);

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCUserTeacherTimetableNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'UserTeacherTimetable',
          uuid_string: id || node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          school_db_name: workerDbName || '',
          school_timetable_id: id || node.id
        };

        setCurrentWorkerNode({
          id: id || node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'UserTeacherTimetable',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to timetable');
    } finally {
      setIsLoading(false);
    }
  };

  const navigateToJournal = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'teaching',
        extended: 'journal'
      }, null, null);

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCUserTeacherTimetableNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'UserTeacherTimetable',
          uuid_string: id || node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          school_db_name: workerDbName || '',
          school_timetable_id: id || node.id
        };

        setCurrentWorkerNode({
          id: id || node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'UserTeacherTimetable',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to journal');
    } finally {
      setIsLoading(false);
    }
  };

  const navigateToPlanner = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'teaching',
        extended: 'planner'
      }, null, null);

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCUserTeacherTimetableNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'UserTeacherTimetable',
          uuid_string: id || node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          school_db_name: workerDbName || '',
          school_timetable_id: id || node.id
        };

        setCurrentWorkerNode({
          id: id || node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'UserTeacherTimetable',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to planner');
    } finally {
      setIsLoading(false);
    }
  };

  const navigateToClass = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'teaching',
        extended: 'classes'
      }, null, null);
      await navigationStore.navigate(id, '');

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCUserTeacherTimetableNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'UserTeacherTimetable',
          uuid_string: node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          school_db_name: workerDbName || '',
          school_timetable_id: node.id
        };

        setCurrentWorkerNode({
          id: node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'UserTeacherTimetable',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to class');
    } finally {
      setIsLoading(false);
    }
  };

  const navigateToLesson = async (id: string) => {
    if (!user?.id) return;
    setIsLoading(true);
    try {
      await navigationStore.switchContext({
        base: 'teaching',
        extended: 'lessons'
      }, null, null);
      await navigationStore.navigate(id, '');

      const node = navigationStore.context.node;
      if (node?.data) {
        const nodeData: CCUserTeacherTimetableNodeProps = {
          ...getBaseNodeProps(),
          __primarylabel__: 'UserTeacherTimetable',
          uuid_string: node.id,
          node_storage_path: node.node_storage_path || '',
          title: node.label,
          school_db_name: workerDbName || '',
          school_timetable_id: node.id
        };

        setCurrentWorkerNode({
          id: node.id,
          label: node.label,
          title: node.label,
          node_storage_path: node.node_storage_path || '',
          type: 'UserTeacherTimetable',
          nodeData
        });
      }
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Failed to navigate to lesson');
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <NeoUserContext.Provider value={{
      userNode,
      calendarNode,
      workerNode,
      userDbName,
      workerDbName,
      isLoading,
      isInitialized,
      error,
      navigateToDay,
      navigateToWeek,
      navigateToMonth,
      navigateToYear,
      navigateToTimetable,
      navigateToJournal,
      navigateToPlanner,
      navigateToClass,
      navigateToLesson,
      currentCalendarNode,
      currentWorkerNode,
      calendarStructure,
      workerStructure
    }}>
      {children}
    </NeoUserContext.Provider>
  );
};

export const useNeoUser = () => useContext(NeoUserContext);
