// components/DatabaseProvider.tsx
import React from 'react';
import { View, ActivityIndicator, ScrollView, Text } from 'react-native';
import { SQLiteProvider, openDatabaseSync, SQLiteDatabase } from 'expo-sqlite';
import { schema } from '@/lib/db/schema';
import { ExerciseService } from '@/lib/db/services/ExerciseService';
import { PublicationQueueService } from '@/lib/db/services/PublicationQueueService';
import { FavoritesService } from '@/lib/db/services/FavoritesService';
import { WorkoutService } from '@/lib/db/services/WorkoutService';
import { TemplateService } from '@/lib/db/services/TemplateService';
import POWRPackService from '@/lib/db/services/POWRPackService';
import { logDatabaseInfo } from '@/lib/db/debug';
import { useNDKStore } from '@/lib/stores/ndk';
import { useLibraryStore } from '@/lib/stores/libraryStore';

// Create context for services
interface DatabaseServicesContextValue {
  exerciseService: ExerciseService | null;
  workoutService: WorkoutService | null;
  templateService: TemplateService | null;
  publicationQueue: PublicationQueueService | null;
  favoritesService: FavoritesService | null;
  powrPackService: POWRPackService | null;
  db: SQLiteDatabase | null;
}

const DatabaseServicesContext = React.createContext<DatabaseServicesContextValue>({
  exerciseService: null,
  workoutService: null,
  templateService: null,
  publicationQueue: null,
  favoritesService: null,
  powrPackService: null,
  db: null,
});

interface DatabaseProviderProps {
  children: React.ReactNode;
}

// Add a DelayedInitializer component to ensure database is fully ready
const DelayedInitializer: React.FC<{children: React.ReactNode}> = ({children}) => {
  const [ready, setReady] = React.useState(false);
  
  React.useEffect(() => {
    // Small delay to ensure database is fully ready
    const timer = setTimeout(() => {
      console.log('[Database] Delayed initialization complete');
      setReady(true);
    }, 300); // 300ms delay should be sufficient
    
    return () => clearTimeout(timer);
  }, []);
  
  if (!ready) {
    return (
      <View className="flex-1 items-center justify-center bg-background">
        <ActivityIndicator size="small" className="mb-2" />
        <Text className="text-foreground text-sm">Finishing initialization...</Text>
      </View>
    );
  }
  
  return <>{children}</>;
};

export function DatabaseProvider({ children }: DatabaseProviderProps) {
  const [isReady, setIsReady] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [services, setServices] = React.useState<DatabaseServicesContextValue>({
    exerciseService: null,
    workoutService: null,
    templateService: null,
    publicationQueue: null,
    favoritesService: null,
    powrPackService: null,
    db: null,
  });
  
  // Get NDK from store to provide to services
  const ndk = useNDKStore(state => state.ndk);
  
  // Effect to set NDK on services when it becomes available
  React.useEffect(() => {
    if (ndk && services.publicationQueue) {
      services.publicationQueue.setNDK(ndk);
    }
  }, [ndk, services]);

  // Effect to trigger initial data refresh when database is ready
  React.useEffect(() => {
    if (isReady && services.db) {
      console.log('[DB] Database ready - triggering initial library refresh');
      // Refresh all library data
      useLibraryStore.getState().refreshAll();
    }
  }, [isReady, services.db]);

  React.useEffect(() => {
    async function initDatabase() {
      try {
        console.log('[DB] Starting database initialization...');
        
        // Add a small delay to ensure system is ready (especially on Android)
        await new Promise(resolve => setTimeout(resolve, 200));
        
        console.log('[DB] Opening database...');
        const db = openDatabaseSync('powr.db');
        
        console.log('[DB] Creating schema...');
        await schema.createTables(db);
        
        // Explicitly check for critical tables after schema creation
        await schema.ensureCriticalTablesExist(db);
        
        // Run migrations with robust error handling
        const runMigration = async (version: string, migrationFn: (db: SQLiteDatabase) => Promise<void>) => {
          try {
            await migrationFn(db);
            console.log(`[DB] Migration ${version} executed successfully`);
          } catch (migrationError) {
            console.warn(`[DB] Error running migration ${version}:`, migrationError);
            // Log more details about the error
            if (migrationError instanceof Error) {
              console.warn(`[DB] Migration error details: ${migrationError.message}`);
              if (migrationError.stack) {
                console.warn(`[DB] Stack trace: ${migrationError.stack}`);
              }
            }
            // Continue even if migration fails - tables might already be updated
          }
        };
        
        // Run migrations
        await runMigration('v8', (schema as any).migrate_v8);
        await runMigration('v9', (schema as any).migrate_v9);
        await runMigration('v10', (schema as any).migrate_v10);

        // Initialize services with error handling
        console.log('[DB] Initializing services...');
        let exerciseService: ExerciseService;
        let workoutService: WorkoutService;
        let templateService: TemplateService;
        let publicationQueue: PublicationQueueService;
        let favoritesService: FavoritesService;
        let powrPackService: POWRPackService;
        
        try {
          exerciseService = new ExerciseService(db);
          console.log('[DB] ExerciseService initialized');
        } catch (error) {
          console.error('[DB] Failed to initialize ExerciseService:', error);
          throw new Error('Failed to initialize ExerciseService');
        }
        
        try {
          workoutService = new WorkoutService(db);
          console.log('[DB] WorkoutService initialized');
        } catch (error) {
          console.error('[DB] Failed to initialize WorkoutService:', error);
          throw new Error('Failed to initialize WorkoutService');
        }
        
        try {
          templateService = new TemplateService(db, exerciseService);
          console.log('[DB] TemplateService initialized');
        } catch (error) {
          console.error('[DB] Failed to initialize TemplateService:', error);
          throw new Error('Failed to initialize TemplateService');
        }
        
        try {
          publicationQueue = new PublicationQueueService(db);
          console.log('[DB] PublicationQueueService initialized');
        } catch (error) {
          console.error('[DB] Failed to initialize PublicationQueueService:', error);
          throw new Error('Failed to initialize PublicationQueueService');
        }
        
        try {
          favoritesService = new FavoritesService(db);
          console.log('[DB] FavoritesService initialized');
        } catch (error) {
          console.error('[DB] Failed to initialize FavoritesService:', error);
          throw new Error('Failed to initialize FavoritesService');
        }
        
        try {
          powrPackService = new POWRPackService(db);
          console.log('[DB] POWRPackService initialized');
        } catch (error) {
          console.error('[DB] Failed to initialize POWRPackService:', error);
          throw new Error('Failed to initialize POWRPackService');
        }
        
        // Initialize the favorites service
        try {
          await favoritesService.initialize();
          console.log('[DB] FavoritesService fully initialized');
        } catch (error) {
          console.error('[DB] Error initializing FavoritesService:', error);
          // Continue even if favorites initialization fails
        }
        
        // Initialize NDK on services if available
        if (ndk) {
          publicationQueue.setNDK(ndk);
        }

        // Set services
        setServices({
          exerciseService,
          workoutService,
          templateService,
          publicationQueue,
          favoritesService,
          powrPackService,
          db,
        });
        
        // Display database info in development mode
        if (__DEV__) {
          await logDatabaseInfo();
        }
        
        console.log('[DB] Database initialized successfully');
        setIsReady(true);
      } catch (e) {
        console.error('[DB] Database initialization failed:', e);
        setError(e instanceof Error ? e.message : 'Database initialization failed');
      }
    }

    initDatabase();
  }, []);

  if (error) {
    return (
      <View className="flex-1 items-center justify-center bg-background p-4">
        <Text className="text-foreground text-lg font-bold mb-2">Database Error</Text>
        <Text className="text-destructive text-sm text-center">{error}</Text>
      </View>
    );
  }

  if (!isReady) {
    return (
      <View className="flex-1 items-center justify-center bg-background">
        <ActivityIndicator size="large" className="mb-4" />
        <Text className="text-foreground text-base">Initializing Database...</Text>
      </View>
    );
  }

  return (
    <SQLiteProvider databaseName="powr.db">
      <DatabaseServicesContext.Provider value={services}>
        <DelayedInitializer>
          {children}
        </DelayedInitializer>
      </DatabaseServicesContext.Provider>
    </SQLiteProvider>
  );
}

// Hooks for accessing services
export function useExerciseService() {
  const context = React.useContext(DatabaseServicesContext);
  if (!context.exerciseService) {
    throw new Error('Exercise service not initialized');
  }
  return context.exerciseService;
}

export function useWorkoutService() {
  const context = React.useContext(DatabaseServicesContext);
  if (!context.workoutService) {
    throw new Error('Workout service not initialized');
  }
  return context.workoutService;
}

export function useTemplateService() {
  const context = React.useContext(DatabaseServicesContext);
  if (!context.templateService) {
    throw new Error('Template service not initialized');
  }
  return context.templateService;
}

export function usePublicationQueue() {
  const context = React.useContext(DatabaseServicesContext);
  if (!context.publicationQueue) {
    throw new Error('Publication queue not initialized');
  }
  return context.publicationQueue;
}

export function useFavoritesService() {
  const context = React.useContext(DatabaseServicesContext);
  if (!context.favoritesService) {
    throw new Error('Favorites service not initialized');
  }
  return context.favoritesService;
}

export function usePOWRPackService() {
  const context = React.useContext(DatabaseServicesContext);
  if (!context.powrPackService) {
    throw new Error('POWR Pack service not initialized');
  }
  return context.powrPackService;
}

export function useDatabase() {
  const context = React.useContext(DatabaseServicesContext);
  if (!context.db) {
    throw new Error('Database not initialized');
  }
  return context.db;
}