import { BunnyService } from './bunny';
import { db } from './db';
import { videos } from '@shared/schema';
import { eq, sql } from 'drizzle-orm';

interface VideoSyncCache {
  videos: any[];
  lastUpdate: number;
  isUpdating: boolean;
}

class VideoSyncService {
  private cache: VideoSyncCache = {
    videos: [],
    lastUpdate: 0,
    isUpdating: false
  };
  private bunnyService: BunnyService;
  private syncInterval: NodeJS.Timeout | null = null;

  constructor() {
    this.bunnyService = new BunnyService();
  }

  private async getAllVideos(): Promise<any[]> {
    let allVideos: any[] = [];
    let page = 1;
    const itemsPerPage = 100; // Maximum per request
    let hasMore = true;
    
    console.log('📥 Starting to fetch all videos with pagination...');
    
    while (hasMore) {
      try {
        console.log(`📄 Fetching page ${page}...`);
        const result = await this.bunnyService.getVideos(page, itemsPerPage);
        
        allVideos = allVideos.concat(result.videos);
        
        // Check if there are more pages
        const totalFetched = allVideos.length;
        hasMore = totalFetched < result.total && result.videos.length > 0;
        
        console.log(`📊 Page ${page}: ${result.videos.length} videos (Total so far: ${allVideos.length}/${result.total})`);
        page++;
        
        // Add small delay to avoid rate limiting
        if (hasMore) {
          await new Promise(resolve => setTimeout(resolve, 100));
        }
        
        // Safety limit to prevent infinite loops
        if (page > 100) {
          console.log('⚠️ Reached page limit (100), stopping fetch');
          break;
        }
        
      } catch (error) {
        console.error(`❌ Error fetching page ${page}:`, error);
        break;
      }
    }
    
    console.log(`✅ Completed pagination fetch: ${allVideos.length} total videos`);
    return allVideos;
  }

  private async syncVideosToDatabase() {
    if (this.cache.videos.length === 0) {
      console.log('⚠️ No videos in cache to sync to database');
      return;
    }

    console.log('🔄 Syncing cached videos to PostgreSQL database...');
    const startTime = Date.now();
    
    let insertedCount = 0;
    let updatedCount = 0;
    let errorCount = 0;
    
    try {
      // First, test database connectivity
      await db.execute(sql`SELECT 1`);
      console.log('📡 Database connection verified');
      
      // Process videos in smaller batches to avoid overwhelming the database
      const batchSize = 10;
      const totalBatches = Math.ceil(this.cache.videos.length / batchSize);
      
      for (let batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
        const start = batchIndex * batchSize;
        const end = Math.min(start + batchSize, this.cache.videos.length);
        const batch = this.cache.videos.slice(start, end);
        
        console.log(`📦 Processing batch ${batchIndex + 1}/${totalBatches} (videos ${start + 1}-${end})`);
        
        for (const video of batch) {
          try {
            // Check if video exists in database using raw SQL
            const existingVideo = await db.execute(sql`SELECT id FROM videos WHERE id = ${video.id} LIMIT 1`);
            
            const videoData = {
              id: video.id,
              title: video.title,
              description: video.description || '',
              thumbnailUrl: video.thumbnailUrl,
              customThumbnailUrl: video.customThumbnailUrl || null,
              videoUrl: video.videoUrl,
              duration: video.duration,
              views: video.views,
              category: video.category || '',
              tags: Array.isArray(video.tags) ? video.tags : [],
              isPublic: video.isPublic !== false,
              createdAt: video.createdAt ? new Date(video.createdAt) : new Date(),
              updatedAt: new Date(),
            };

            if (existingVideo.rows.length === 0) {
              // Insert new video using raw SQL to avoid schema issues
              await db.execute(sql`
                INSERT INTO videos (id, title, description, thumbnail_url, video_url, duration, views, category, custom_thumbnail_url, tags, is_public, created_at, updated_at)
                VALUES (${videoData.id}, ${videoData.title}, ${videoData.description}, ${videoData.thumbnailUrl}, ${videoData.videoUrl}, ${videoData.duration}, ${videoData.views}, ${videoData.category}, ${videoData.customThumbnailUrl}, ${'{' + videoData.tags.join(',') + '}'}, ${videoData.isPublic}, ${videoData.createdAt.toISOString()}, ${videoData.updatedAt.toISOString()})
              `);
              insertedCount++;
            } else {
              // Update existing video using raw SQL
              await db.execute(sql`
                UPDATE videos 
                SET title = ${videoData.title}, description = ${videoData.description}, thumbnail_url = ${videoData.thumbnailUrl}, 
                    video_url = ${videoData.videoUrl}, duration = ${videoData.duration}, views = ${videoData.views}, 
                    category = ${videoData.category}, custom_thumbnail_url = ${videoData.customThumbnailUrl}, 
                    tags = ${'{' + videoData.tags.join(',') + '}'}, is_public = ${videoData.isPublic}, updated_at = ${videoData.updatedAt.toISOString()}
                WHERE id = ${video.id}
              `);
              updatedCount++;
            }
          } catch (error) {
            console.error(`❌ Failed to sync video ${video.id}:`, error);
            errorCount++;
            // Continue with other videos
          }
        }
        
        // Small delay between batches to avoid overwhelming the database
        if (batchIndex < totalBatches - 1) {
          await new Promise(resolve => setTimeout(resolve, 50));
        }
      }
      
      const duration = Date.now() - startTime;
      console.log(`✅ Database sync completed in ${duration}ms:`);
      console.log(`   📥 Inserted: ${insertedCount} new videos`);
      console.log(`   🔄 Updated: ${updatedCount} existing videos`);
      console.log(`   ❌ Errors: ${errorCount} videos`);
      console.log(`   📊 Database total: ${insertedCount + updatedCount} videos`);
      console.log(`   🎥 Cache total: ${this.cache.videos.length} videos`);
      
    } catch (error) {
      console.error('❌ Database sync failed:', error);
      throw error; // Re-throw to be caught by timeout wrapper
    }
  }

  async initialize() {
    console.log('🔄 Initializing video sync service...');
    try {
      await this.syncVideos();
      
      // Add timeout protection for database sync
      const syncTimeout = new Promise((_, reject) => 
        setTimeout(() => reject(new Error('Database sync timeout after 30 seconds')), 30000)
      );
      
      await Promise.race([
        this.syncVideosToDatabase(),
        syncTimeout
      ]);
      
      this.startPeriodicSync();
      console.log('✅ Video sync service initialized successfully');
    } catch (error) {
      console.error('❌ Failed to initialize video sync service:', error);
      console.log('⚠️ Continuing without database sync - app will still work with cached data');
      // Continue without crashing the server
    }
  }

  private async syncVideos() {
    if (this.cache.isUpdating) {
      console.log('⏳ Video sync already in progress, skipping...');
      return;
    }

    this.cache.isUpdating = true;
    const startTime = Date.now();
    
    try {
      console.log('🔍 Fetching ALL videos from Bunny.net...');
      const allVideos = await this.getAllVideos();
      
      this.cache.videos = allVideos;
      this.cache.lastUpdate = Date.now();
      
      const duration = Date.now() - startTime;
      console.log(`✅ Video sync completed: ${allVideos.length} videos cached in ${duration}ms`);
    } catch (error) {
      console.error('❌ Video sync failed:', error);
    } finally {
      this.cache.isUpdating = false;
    }
  }

  private startPeriodicSync() {
    // Sync every 60 seconds
    this.syncInterval = setInterval(() => {
      console.log('⏰ Starting scheduled video sync...');
      this.syncVideos();
    }, 60 * 1000);
    
    console.log('📅 Scheduled video sync every 60 seconds');
  }

  getVideos(limit: number = 20, offset: number = 0, search?: string) {
    let filteredVideos = this.cache.videos;

    // Fast client-side search
    if (search && search.length >= 2) {
      const searchLower = search.toLowerCase();
      filteredVideos = this.cache.videos.filter(video => 
        video.title.toLowerCase().includes(searchLower) ||
        video.description?.toLowerCase().includes(searchLower)
      );
    }

    const paginatedVideos = filteredVideos.slice(offset, offset + limit);
    
    return {
      videos: paginatedVideos,
      total: filteredVideos.length,
      hasMore: offset + limit < filteredVideos.length,
      cacheAge: Date.now() - this.cache.lastUpdate
    };
  }

  async getVideo(id: string) {
    // First try cache
    const cachedVideo = this.cache.videos.find(v => v.id === id);
    if (cachedVideo) {
      return cachedVideo;
    }

    // Fallback to direct API call
    return await this.bunnyService.getVideo(id);
  }

  getCacheStats() {
    return {
      videosCount: this.cache.videos.length,
      lastUpdate: this.cache.lastUpdate,
      isUpdating: this.cache.isUpdating,
      cacheAge: Date.now() - this.cache.lastUpdate
    };
  }

  stop() {
    if (this.syncInterval) {
      clearInterval(this.syncInterval);
      this.syncInterval = null;
      console.log('🛑 Video sync service stopped');
    }
  }
}

export const videoSyncService = new VideoSyncService();