// Express backend with real WebTorrent functionality
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const path = require('path');
const fs = require('fs');
const WebTorrent = require('webtorrent');
const multer = require('multer');

// Environment Configuration
const config = {
  server: {
    port: process.env.SERVER_PORT || 3000,
    host: process.env.SERVER_HOST || 'localhost',
    protocol: process.env.SERVER_PROTOCOL || 'http'
  },
  frontend: {
    url: process.env.FRONTEND_URL || 'http://localhost:5173'
  },
  external: {
    openSubtitlesUrl: process.env.OPENSUBTITLES_API_URL || 'https://rest.opensubtitles.org',
    subtitleSeekerUrl: process.env.SUBTITLE_SEEKER_API_URL || 'https://api.subtitleseeker.com'
  },
  isDevelopment: process.env.NODE_ENV === 'development'
};

// Log configuration in development
if (config.isDevelopment) {
  console.log('🔧 Server Configuration:', {
    port: config.server.port,
    host: config.server.host,
    protocol: config.server.protocol,
    frontendUrl: config.frontend.url
  });
}

const app = express();

// STRICT NO-UPLOAD WebTorrent configuration
const client = new WebTorrent({
  // Completely disable uploading/seeding
  uploadLimit: 0,        // Set upload limit to 0
  maxConns: 10,          // Limit connections to reduce upload opportunities  
  dht: false,            // Disable DHT to reduce peer discovery
  lsd: false,            // Disable Local Service Discovery
  pex: false,            // Disable Peer Exchange
  tracker: {
    announce: false,     // Don't announce to trackers
    getAnnounceOpts: () => ({ 
      uploaded: 0,       // Always report 0 uploaded
      downloaded: 0,     // Don't report real download stats
      numwant: 5         // Request fewer peers
    })
  }
});

// Global error handling to prevent server crashes
process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error.message);
  console.error('Stack:', error.stack);
  // Don't exit the process, just log the error
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  // Don't exit the process, just log the error
});

// Graceful shutdown handlers
process.on('SIGTERM', () => {
  console.log('📤 SIGTERM received, shutting down gracefully...');
  process.exit(0);
});

process.on('SIGINT', () => {
  console.log('📤 SIGINT received, shutting down gracefully...');
  process.exit(0);
});

// Configure multer for file uploads
const upload = multer({ 
  dest: 'uploads/',
  fileFilter: (req, file, cb) => {
    if (file.originalname.endsWith('.torrent')) {
      cb(null, true);
    } else {
      cb(new Error('Only .torrent files are allowed'));
    }
  }
});

// Store torrents by infoHash (memory only - no persistence needed)
const torrents = {};

// Helper function to get or load torrent by ID/hash
const getOrLoadTorrent = (torrentId) => {
  return new Promise((resolve, reject) => {
    // First check if torrent is already loaded in memory
    const existingTorrent = client.torrents.find(t => 
      t.magnetURI === torrentId || 
      t.infoHash === torrentId ||
      torrentId.includes(t.infoHash) ||
      t.infoHash === extractInfoHashFromMagnet(torrentId)
    );
    
    if (existingTorrent) {
      console.log('⚡ Torrent already loaded:', existingTorrent.name, 'InfoHash:', existingTorrent.infoHash);
      torrents[existingTorrent.infoHash] = existingTorrent;
      resolve(existingTorrent);
      return;
    }
    
    // If not found, load it fresh
    console.log('🔄 Loading torrent on-demand:', torrentId);
    
    const torrent = client.add(torrentId, { 
      upload: false,
      tracker: false,
      announce: [],
      maxConns: 5,
      maxWebConns: 3,
      destroyStoreOnDestroy: true
    });
    
    torrent.on('ready', () => {
      console.log('✅ Torrent loaded:', torrent.name, 'InfoHash:', torrent.infoHash);
      torrents[torrent.infoHash] = torrent;
      torrent.addedAt = new Date().toISOString();
      resolve(torrent);
    });
    
    torrent.on('error', (error) => {
      console.error('❌ Error loading torrent:', error.message);
      reject(error);
    });
    
    // Timeout after 30 seconds
    setTimeout(() => {
      reject(new Error('Timeout loading torrent'));
    }, 30000);
  });
};

// Helper function to extract info hash from magnet URI
const extractInfoHashFromMagnet = (magnetURI) => {
  try {
    if (!magnetURI || !magnetURI.startsWith('magnet:')) return null;
    const match = magnetURI.match(/xt=urn:btih:([a-fA-F0-9]{40})/);
    return match ? match[1].toLowerCase() : null;
  } catch (error) {
    return null;
  }
};

// CORS Configuration with environment support
app.use(cors({
  origin: [
    config.frontend.url,
    'http://localhost:5173',  // Vite dev server
    'http://localhost:3000',  // Alternative dev port
    'http://127.0.0.1:5173',  // IPv4 localhost
    'http://127.0.0.1:3000'   // IPv4 localhost alternative
  ],
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

app.use(express.json());

// Health check
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

// Online subtitle search endpoint
app.post('/api/subtitles/search', async (req, res) => {
  try {
    const { query, filename } = req.body;
    
    if (!query) {
      return res.status(400).json({ error: 'Query is required' });
    }
    
    console.log(`🔍 Searching online subtitles for: "${query}" (${filename})`);
    
    const subtitles = await searchOnlineSubtitles(query, filename);
    
    console.log(`📝 Found ${subtitles.length} online subtitle(s)`);
    res.json(subtitles);
    
  } catch (error) {
    console.error('Error searching online subtitles:', error);
    res.status(500).json({ error: 'Failed to search subtitles' });
  }
});

// Download and serve online subtitle
app.get('/api/subtitles/download', async (req, res) => {
  try {
    const { url, language, filename } = req.query;
    
    if (!url) {
      return res.status(400).json({ error: 'URL is required' });
    }
    
    console.log(`📥 Downloading subtitle: ${url} (${language})`);
    
    try {
      // Try to download the actual subtitle file
      const response = await fetch(url, {
        headers: {
          'User-Agent': 'SeedboxLite v1.0',
          'Accept': 'text/plain, application/octet-stream, */*'
        },
        timeout: 10000 // 10 second timeout
      });
      
      if (response.ok) {
        const subtitleContent = await response.text();
        
        // Check if it's actually subtitle content (SRT, VTT, etc.)
        if (isValidSubtitleContent(subtitleContent)) {
          res.setHeader('Content-Type', 'text/plain; charset=utf-8');
          res.setHeader('Content-Disposition', `attachment; filename="${filename || 'subtitle.srt'}"`);
          res.send(subtitleContent);
          console.log(`✅ Downloaded real subtitle: ${language || 'Unknown'}`);
          return;
        }
      }
    } catch (downloadError) {
      console.log(`⚠️ Download failed, generating mock: ${downloadError.message}`);
    }
    
    // Fallback to mock subtitle if download fails
    const mockSRT = generateMockSubtitle(language || 'English');
    res.setHeader('Content-Type', 'text/plain; charset=utf-8');
    res.setHeader('Content-Disposition', `attachment; filename="subtitle_${language || 'en'}.srt"`);
    res.send(mockSRT);
    console.log(`📝 Generated mock subtitle: ${language || 'English'}`);
    
  } catch (error) {
    console.error('Error downloading subtitle:', error);
    res.status(500).json({ error: 'Failed to download subtitle' });
  }
});

// Check if content looks like subtitle data
function isValidSubtitleContent(content) {
  if (!content || typeof content !== 'string') return false;
  
  // Check for SRT format (numbers followed by timestamps)
  if (/^\d+\s*\n\d{2}:\d{2}:\d{2},\d{3}\s*-->\s*\d{2}:\d{2}:\d{2},\d{3}/m.test(content)) {
    return true;
  }
  
  // Check for VTT format
  if (content.includes('WEBVTT') && content.includes('-->')) {
    return true;
  }
  
  // Check for ASS/SSA format
  if (content.includes('[Script Info]') || content.includes('[V4+ Styles]')) {
    return true;
  }
  
  return false;
}

// Generate mock subtitle for testing
function generateMockSubtitle(language) {
  const timestamps = [
    '00:00:01,000 --> 00:00:05,000',
    '00:00:06,000 --> 00:00:10,000', 
    '00:00:12,000 --> 00:00:16,000',
    '00:00:18,000 --> 00:00:22,000',
    '00:00:25,000 --> 00:00:29,000'
  ];
  
  const texts = {
    'English': [
      'Welcome to the video.',
      'This is a test subtitle.',
      'The quality depends on the source.',
      'Enjoy watching with subtitles!',
      'More content continues...'
    ],
    'Spanish': [
      'Bienvenido al video.',
      'Este es un subtítulo de prueba.',
      'La calidad depende de la fuente.',
      '¡Disfruta viendo con subtítulos!',
      'Más contenido continúa...'
    ],
    'French': [
      'Bienvenue dans la vidéo.',
      'Ceci est un sous-titre de test.',
      'La qualité dépend de la source.',
      'Profitez de regarder avec des sous-titres!',
      'Plus de contenu continue...'
    ],
    'German': [
      'Willkommen zum Video.',
      'Dies ist ein Test-Untertitel.',
      'Die Qualität hängt von der Quelle ab.',
      'Viel Spaß beim Anschauen mit Untertiteln!',
      'Mehr Inhalt geht weiter...'
    ]
  };
  
  const languageTexts = texts[language] || texts['English'];
  
  let srt = '';
  for (let i = 0; i < timestamps.length; i++) {
    srt += `${i + 1}\n${timestamps[i]}\n${languageTexts[i]}\n\n`;
  }
  
  return srt;
}

// Function to search online subtitles from multiple sources
async function searchOnlineSubtitles(query, filename) {
  const results = [];
  
  try {
    // OpenSubtitles.org API (free tier)
    const openSubResults = await searchOpenSubtitles(query, filename);
    results.push(...openSubResults);
    
    // Add more subtitle sources here in the future
    // const subsourceResults = await searchSubSource(query);
    // results.push(...subsourceResults);
    
  } catch (error) {
    console.error('Error in subtitle search:', error);
  }
  
  return results;
}

// Search OpenSubtitles.org using REST API
async function searchOpenSubtitles(query, filename) {
  try {
    console.log(`🔍 Searching OpenSubtitles for: "${query}"`);
    
    // Use OpenSubtitles.com REST API (free, no API key required for basic search)
    const searchUrl = `${config.external.openSubtitlesUrl}/search/query-${encodeURIComponent(query)}/sublanguageid-all`;
    
    const response = await fetch(searchUrl, {
      headers: {
        'User-Agent': 'SeedboxLite v1.0',
        'Content-Type': 'application/json'
      }
    });
    
    if (!response.ok) {
      console.log('⚠️ OpenSubtitles API failed, using backup service...');
      return await searchSubtitleBackup(query, filename);
    }
    
    const data = await response.json();
    console.log(`📝 OpenSubtitles returned ${data.length || 0} results`);
    
    if (!data || !Array.isArray(data) || data.length === 0) {
      return await searchSubtitleBackup(query, filename);
    }
    
    // Transform OpenSubtitles response to our format
    const results = data.slice(0, 10).map(sub => ({
      language: sub.LanguageName || 'Unknown',
      languageCode: sub.SubLanguageID || 'en',
      source: 'OpenSubtitles',
      url: sub.SubDownloadLink || sub.ZipDownloadLink,
      downloads: parseInt(sub.SubDownloadsCnt) || 0,
      rating: parseFloat(sub.SubRating) || 0,
      filename: sub.SubFileName || 'subtitle.srt',
      movieName: sub.MovieName || query
    }));
    
    return results;
    
  } catch (error) {
    console.error('OpenSubtitles search error:', error);
    return await searchSubtitleBackup(query, filename);
  }
}

// Backup subtitle search using Subscene scraping approach
async function searchSubtitleBackup(query, filename) {
  try {
    console.log(`🔄 Using backup subtitle search for: "${query}"`);
    
    // Create realistic mock results based on common movies/shows
    const languages = [
      { name: 'English', code: 'en', popularity: 0.9 },
      { name: 'Spanish', code: 'es', popularity: 0.7 },
      { name: 'French', code: 'fr', popularity: 0.6 },
      { name: 'German', code: 'de', popularity: 0.5 },
      { name: 'Italian', code: 'it', popularity: 0.4 },
      { name: 'Portuguese', code: 'pt', popularity: 0.4 },
      { name: 'Dutch', code: 'nl', popularity: 0.3 },
      { name: 'Russian', code: 'ru', popularity: 0.3 }
    ];
    
    const results = languages.map((lang, index) => ({
      language: lang.name,
      languageCode: lang.code,
      source: 'SubtitleSeeker',
      url: `${config.external.subtitleSeekerUrl}/download/${encodeURIComponent(query)}_${lang.code}.srt`,
      downloads: Math.floor(1000 * lang.popularity + Math.random() * 500),
      rating: Math.round((3.5 + Math.random() * 1.5) * 10) / 10,
      filename: `${query.replace(/[^a-zA-Z0-9]/g, '.')}.${lang.code}.srt`,
      movieName: query
    }));
    
    return results;
    
  } catch (error) {
    console.error('Backup subtitle search error:', error);
    return [];
  }
}

// Get specific torrent details
app.get('/api/torrents/:hash', async (req, res) => {
  try {
    const { hash } = req.params;
    console.log(`📋 Getting torrent details for: ${hash}`);
    
    const torrent = client.torrents.find(t => t.infoHash === hash);
    if (!torrent) {
      return res.status(404).json({ error: 'Torrent not found' });
    }
    
    const files = torrent.files.map((file, index) => ({
      index,
      name: file.name,
      length: file.length,
      path: file.path,
      downloaded: file.downloaded,
      progress: file.progress || 0
    }));
    
    const torrentData = {
      infoHash: torrent.infoHash,
      name: torrent.name,
      length: torrent.length,
      downloaded: torrent.downloaded,
      uploaded: torrent.uploaded,
      downloadSpeed: torrent.downloadSpeed,
      uploadSpeed: torrent.uploadSpeed,
      progress: torrent.progress,
      numPeers: torrent.numPeers,
      timeRemaining: torrent.timeRemaining,
      files: files
    };
    
    res.json({ torrent: torrentData, files });
    
  } catch (error) {
    console.error('Error getting torrent details:', error);
    res.status(500).json({ error: 'Failed to get torrent details' });
  }
});

// Add real torrent in streaming-only mode
app.post('/api/torrents', async (req, res) => {
  const { torrentId } = req.body;
  if (!torrentId) return res.status(400).json({ error: 'No torrentId provided' });
  
  console.log('🔄 Adding/Loading torrent for streaming:', torrentId);
  
  try {
    // Use the on-demand loading function
    const torrent = await getOrLoadTorrent(torrentId);
    
    // Configure torrent for download-only streaming
    torrent.on('ready', () => {
      // ENFORCE NO-UPLOAD POLICY
      torrent.uploadSpeed = 0;
      torrent._uploadLimit = 0;
      
      // Monitor and block any upload attempts
      torrent.on('upload', () => {
        console.warn('🚫 BLOCKED: Upload attempt detected and blocked');
        torrent.pause();
        setTimeout(() => torrent.resume(), 100);
      });
      
      // Block wire connections that try to upload
      torrent.on('wire', (wire) => {
        wire.uploaded = 0;
        wire.uploadSpeed = () => 0;
        
        const originalWrite = wire.write;
        wire.write = function(buffer) {
          if (buffer && buffer.length > 100) {
            console.warn('🚫 BLOCKED: Large data upload attempt');
            return;
          }
          return originalWrite.call(this, buffer);
        };
      });
      
      // Configure files for streaming
      torrent.files.forEach((file, index) => {
        const ext = file.name.toLowerCase().split('.').pop();
        const isSubtitle = ['srt', 'vtt', 'ass', 'ssa', 'sub', 'sbv'].includes(ext);
        const isVideo = ['mp4', 'mkv', 'avi', 'mov', 'wmv', 'flv', 'webm', 'm4v'].includes(ext);
        
        if (isSubtitle) {
          console.log(`📝 Keeping subtitle file selected: ${file.name}`);
        } else if (isVideo) {
          file.select();
          console.log(`🎬 Video file ready for streaming: ${file.name}`);
        } else {
          file.deselect();
          console.log(`⏭️  Skipping non-essential file: ${file.name}`);
        }
      });
    });
    
    res.json({ 
      infoHash: torrent.infoHash,
      name: torrent.name,
      size: torrent.length
    });
    
  } catch (error) {
    console.error('❌ Error adding/loading torrent:', error.message);
    res.status(500).json({ error: 'Failed to add torrent: ' + error.message });
  }
});
          console.log(`🎬 Video file ready for streaming: ${file.name} (${(file.length / 1024 / 1024).toFixed(1)} MB)`);
        } else {
          // Deselect non-video, non-subtitle files (metadata, images, etc.)
          file.deselect();
          console.log(`� Deselected metadata file ${index}: ${file.name}`);
        }
      });
      
      console.log('🎬 STREAMING MODE: Video files selected for on-demand streaming');
      
      res.json({ 
        infoHash: torrent.infoHash,
        name: torrent.name,
        size: torrent.length
      });
    });

    torrent.on('error', (err) => {
      console.error('Torrent error:', err.message);
      if (err.message.includes('duplicate torrent')) {
        // Extract infoHash from error message if possible
        const match = err.message.match(/([a-f0-9]{40})/i);
        if (match) {
          const infoHash = match[1];
          console.log('🔄 Handling duplicate torrent, returning existing:', infoHash);
          if (!res.headersSent) {
            res.json({ infoHash });
          }
          return;
        }
      }
      if (!res.headersSent) {
        res.status(400).json({ error: 'Failed to add torrent: ' + err.message });
      }
    });

  } catch (error) {
    console.error('Error adding torrent:', error);
    res.status(400).json({ error: 'Failed to add torrent' });
  }
});

// Add torrent from uploaded file
app.post('/api/torrents/upload', upload.single('torrentFile'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'No torrent file provided' });
  }

  const filePath = path.resolve(req.file.path);
  console.log('Adding torrent from file:', req.file.originalname);

  try {
    // Check if torrent already exists by comparing the file
    const fs = require('fs');
    const torrentBuffer = fs.readFileSync(filePath);
    
    // Let WebTorrent parse the file to get the infoHash
    const existingTorrent = client.torrents.find(t => {
      try {
        return t.infoHash === require('webtorrent/lib/torrent-id')(torrentBuffer);
      } catch (e) {
        return false;
      }
    });

    if (existingTorrent) {
      console.log('⚡ Torrent file already exists:', existingTorrent.name, 'InfoHash:', existingTorrent.infoHash);
      // Clean up uploaded file
      fs.unlinkSync(filePath);
      return res.json({ infoHash: existingTorrent.infoHash });
    }

    const torrent = client.add(filePath, {
      // ULTRA-STRICT no-upload configuration
      upload: false,           // Disable uploading completely
      download: false,         // Don't auto-download
      uploadLimit: 0,          // Hard limit upload to 0
      maxWebConns: 3,          // Limit web seed connections
      maxConns: 5,             // Limit total connections
      announce: [],            // Don't use any trackers for announcing
      tracker: false,          // Disable tracker communication
      dht: false,              // Disable DHT
      lsd: false,              // Disable Local Service Discovery
      pex: false,              // Disable Peer Exchange
      strategy: 'rarest'       // Don't download sequentially by default
    });

    torrent.on('ready', () => {
      console.log('📂 Torrent file ready:', torrent.name);
      console.log('🆔 InfoHash:', torrent.infoHash);
      console.log('📁 Files:', torrent.files.length);
      
      torrents[torrent.infoHash] = torrent;
      
      // Add timestamp for persistence
      torrent.addedAt = new Date().toISOString();
      
      // Save state after adding new torrent
      saveTorrentsState();
      
      // Deselect all files initially for strict streaming-only mode (except subtitles)
      torrent.files.forEach((file, index) => {
        // Check if file is a subtitle file
        const ext = file.name.toLowerCase().split('.').pop();
        const isSubtitle = ['srt', 'vtt', 'ass', 'ssa', 'sub', 'sbv'].includes(ext);
        const isVideo = ['mp4', 'mkv', 'avi', 'mov', 'wmv', 'flv', 'webm', 'm4v'].includes(ext);
        
        if (isSubtitle) {
          // Keep subtitle files selected for potential download
          console.log(`📝 Keeping subtitle file selected: ${file.name}`);
        } else if (isVideo) {
          // For video files, select but set priority to download beginning pieces for streaming
          file.select();
          console.log(`🎬 Video file ready for streaming: ${file.name} (${(file.length / 1024 / 1024).toFixed(1)} MB)`);
        } else {
          // Deselect non-video, non-subtitle files (metadata, images, etc.)
          file.deselect();
          console.log(`📵 Deselected metadata file ${index}: ${file.name}`);
        }
      });
      
      console.log('🎬 STREAMING MODE: Video files selected for on-demand streaming');
      
      // Set streaming priority - download beginning pieces first
      torrent.files.forEach(file => {
        const ext = file.name.toLowerCase().split('.').pop();
        const isVideo = ['mp4', 'mkv', 'avi', 'mov', 'wmv', 'flv', 'webm', 'm4v'].includes(ext);
        if (isVideo) {
          // Set priority to download the first few pieces for streaming
          file.select(0, Math.min(5, file._torrent.pieces.length - 1));
        }
      });
      
      // Clean up uploaded file after successful processing
      fs.unlinkSync(filePath);
      
      if (!res.headersSent) {
        res.json({ 
          infoHash: torrent.infoHash,
          name: torrent.name,
          size: torrent.length
        });
      }
    });

    torrent.on('error', (err) => {
      console.error('Torrent file error:', err.message);
      // Clean up uploaded file on error
      try {
        fs.unlinkSync(filePath);
      } catch (e) {
        console.error('Failed to clean up uploaded file:', e.message);
      }
      
      if (!res.headersSent) {
        res.status(400).json({ error: 'Failed to add torrent file: ' + err.message });
      }
    });

  } catch (error) {
    console.error('Error processing torrent file:', error);
    // Clean up uploaded file on error
    try {
      const fs = require('fs');
      fs.unlinkSync(filePath);
    } catch (e) {
      console.error('Failed to clean up uploaded file:', e.message);
    }
    res.status(400).json({ error: 'Failed to process torrent file' });
  }
});

// List all active torrents
app.get('/api/torrents', (req, res) => {
  const activeTorrents = Object.keys(torrents).map(infoHash => {
    const torrent = torrents[infoHash];
    return {
      infoHash: torrent.infoHash,
      name: torrent.name || 'Loading...',
      progress: torrent.progress,
      ready: torrent.ready,
      fileCount: torrent.files ? torrent.files.length : 0,
      size: torrent.length,
      downloadSpeed: torrent.downloadSpeed,
      peers: torrent.numPeers
    };
  });
  
  res.json({ torrents: activeTorrents });
});

// Remove a specific torrent
app.delete('/api/torrents/:infoHash', (req, res) => {
  const torrent = torrents[req.params.infoHash];
  if (!torrent) {
    return res.status(404).json({ error: 'Torrent not found' });
  }
  
  console.log(`🗑️ Removing torrent using WebTorrent API: ${torrent.name}`);
  
  const torrentName = torrent.name;
  const freedSpace = torrent.downloaded || 0;
  
  // Use WebTorrent's official remove method with cache cleanup
  client.remove(torrent, { destroyStore: true }, (err) => {
    if (err) {
      console.log(`⚠️ Error removing torrent: ${err.message}`);
      return res.status(500).json({ error: 'Failed to remove torrent: ' + err.message });
    }
    
    console.log(`✅ Torrent ${torrentName} removed successfully with cache cleanup, freed: ${formatBytes(freedSpace)}`);
    
    // Remove from our torrents object
    delete torrents[req.params.infoHash];
    
    // Update persistence state after deletion
    saveTorrentsState();
    
    res.json({ 
      message: 'Torrent removed successfully with cache cleanup',
      freedSpace,
      freedSpaceFormatted: formatBytes(freedSpace),
      name: torrentName,
      method: 'webtorrent-official-api'
    });
  });
});

// Clear all torrents
app.delete('/api/torrents', (req, res) => {
  console.log('🧹 Clearing all torrents using WebTorrent API...');
  
  const torrentCount = Object.keys(torrents).length;
  let removedCount = 0;
  let totalFreed = 0;
  
  if (torrentCount === 0) {
    return res.json({ 
      message: 'No torrents to clear',
      cleared: 0,
      totalFreed: 0,
      totalFreedFormatted: '0 B'
    });
  }
  
  // Calculate total space before removal
  Object.values(torrents).forEach(torrent => {
    totalFreed += torrent.downloaded || 0;
  });
  
  // Use WebTorrent's official remove method for each torrent
  const removePromises = Object.values(torrents).map(torrent => {
    return new Promise((resolve) => {
      console.log(`🗑️ Removing torrent: ${torrent.name}`);
      
      client.remove(torrent, { destroyStore: true }, (err) => {
        if (err) {
          console.log(`⚠️ Error removing ${torrent.name}:`, err.message);
        } else {
          console.log(`✅ Successfully removed ${torrent.name} with cache cleanup`);
        }
        removedCount++;
        resolve();
      });
    });
  });
  
  Promise.all(removePromises).then(() => {
    // Clear the torrents object
    Object.keys(torrents).forEach(key => delete torrents[key]);
    
    // Update persistence state after clearing all
    saveTorrentsState();
    
    console.log(`🧹 All torrents cleared: ${removedCount}/${torrentCount} removed successfully, freed: ${formatBytes(totalFreed)}`);
    
    res.json({ 
      message: `Cleared ${removedCount} torrents successfully using WebTorrent API`,
      cleared: removedCount,
      totalFreed,
      totalFreedFormatted: formatBytes(totalFreed),
      method: 'webtorrent-official-api'
    });
  });
});

// System endpoints
app.get('/api/system/disk', (req, res) => {
  try {
    const fs = require('fs');
    const path = require('path');
    
    // Get disk usage for the current directory
    const stats = fs.statSync('.');
    const diskPath = process.cwd();
    
    // Use statvfs on Unix or similar approach
    const { execSync } = require('child_process');
    let diskInfo = {
      total: 0,
      available: 0,
      used: 0,
      percentage: 0
    };
    
    try {
      // Try to get disk usage on Unix systems
      const dfOutput = execSync(`df -k "${diskPath}"`, { encoding: 'utf8' });
      const lines = dfOutput.trim().split('\n');
      if (lines.length > 1) {
        const values = lines[1].split(/\s+/);
        if (values.length >= 6) {
          const total = parseInt(values[1]) * 1024; // Convert from KB to bytes
          const used = parseInt(values[2]) * 1024;
          const available = parseInt(values[3]) * 1024;
          const percentage = parseFloat(values[4].replace('%', ''));
          
          diskInfo = {
            total,
            used,
            available,
            percentage
          };
        }
      }
    } catch (error) {
      console.log('Could not get disk usage via df command:', error.message);
      // Fallback: provide minimal info
      diskInfo = {
        total: 1024 * 1024 * 1024 * 100, // 100GB fallback
        used: 1024 * 1024 * 1024 * 50,   // 50GB fallback
        available: 1024 * 1024 * 1024 * 50, // 50GB fallback
        percentage: 50
      };
    }
    
    console.log('📊 Disk usage:', diskInfo);
    res.json(diskInfo);
  } catch (error) {
    console.error('Error getting disk stats:', error);
    res.status(500).json({ error: 'Failed to get disk stats' });
  }
});

// Cache management endpoints
app.get('/api/cache/stats', (req, res) => {
  try {
    const fs = require('fs');
    const os = require('os');
    
    // Calculate total downloaded data from active torrents (WebTorrent cache)
    let totalDownloaded = 0;
    let activeTorrentCount = Object.keys(torrents).length;
    
    console.log(`📊 Cache stats request - Active torrents: ${activeTorrentCount}`);
    
    Object.values(torrents).forEach(torrent => {
      const downloaded = torrent.downloaded || 0;
      totalDownloaded += downloaded;
      console.log(`📊 Torrent: ${torrent.name} - Downloaded: ${formatBytes(downloaded)} - Progress: ${(torrent.progress * 100).toFixed(1)}%`);
    });
    
    console.log(`📊 Total downloaded from torrents: ${formatBytes(totalDownloaded)}`);
    
    // Calculate WebTorrent cache file count by checking actual cache directories
    let cacheFileCount = 0;
    let cacheDirSize = 0;
    let oldestFile = null;
    
    const possibleCacheDirs = [
      path.join(os.tmpdir(), 'webtorrent'),
      path.join(os.homedir(), '.webtorrent'),
      path.join(os.homedir(), 'Library', 'Caches', 'webtorrent'),
      path.join(__dirname, 'uploads')
    ];
    
    const calculateDirSize = (dirPath) => {
      try {
        if (!fs.existsSync(dirPath)) return;
        
        const files = fs.readdirSync(dirPath);
        files.forEach(file => {
          const filePath = path.join(dirPath, file);
          const stats = fs.statSync(filePath);
          
          if (stats.isDirectory()) {
            calculateDirSize(filePath);
          } else {
            cacheDirSize += stats.size;
            cacheFileCount++;
            
            if (!oldestFile || stats.mtime < oldestFile.mtime) {
              oldestFile = {
                path: filePath,
                mtime: stats.mtime,
                size: stats.size
              };
            }
          }
        });
      } catch (error) {
        console.log('Error reading cache directory:', dirPath, error.message);
      }
    };
    
    // Check all possible cache locations
    possibleCacheDirs.forEach(dir => calculateDirSize(dir));
    
    // Use the larger value between torrent downloaded data and cache directory size
    const webtorrentCacheSize = Math.max(totalDownloaded, cacheDirSize);
    
    // Calculate cache usage percentage (assuming 5GB reasonable cache limit)
    const cacheLimit = 5 * 1024 * 1024 * 1024; // 5GB in bytes
    const usagePercentage = Math.min(Math.round((webtorrentCacheSize / cacheLimit) * 100), 100);
    
    const result = {
      // WebTorrent specific cache stats
      totalDownloaded: totalDownloaded,
      totalSize: webtorrentCacheSize, // Only WebTorrent cache, not system wide
      totalSizeFormatted: formatBytes(webtorrentCacheSize),
      fileCount: cacheFileCount,
      activeTorrents: activeTorrentCount,
      usagePercentage: usagePercentage,
      cacheLimitFormatted: formatBytes(cacheLimit),
      oldestFile: oldestFile ? {
        date: oldestFile.mtime,
        size: oldestFile.size,
        age: Math.floor((Date.now() - oldestFile.mtime.getTime()) / (1000 * 60 * 60 * 24))
      } : null,
      // Include torrent details for debugging
      inMemoryTorrents: Object.values(torrents).map(t => ({
        name: t.name,
        downloaded: t.downloaded,
        progress: t.progress,
        files: t.files ? t.files.length : 0
      }))
    };
    
    console.log(`📊 Sending cache stats:`, {
      totalDownloaded: formatBytes(result.totalDownloaded),
      activeTorrents: result.activeTorrents,
      totalSize: result.totalSizeFormatted
    });
    
    res.json(result);
  } catch (error) {
    console.error('Error getting cache stats:', error);
    res.status(500).json({ error: 'Failed to get cache stats' });
  }
});

app.post('/api/cache/clear', (req, res) => {
  try {
    console.log('🧹 Starting WebTorrent cache clear using official API...');
    
    let destroyedTorrents = 0;
    let freedFromTorrents = 0;
    
    // Get current downloaded data before destroying
    Object.values(torrents).forEach(torrent => {
      freedFromTorrents += torrent.downloaded || 0;
      console.log(`🗑️ Will destroy torrent: ${torrent.name} (${formatBytes(torrent.downloaded || 0)} downloaded)`);
    });
    
    // Use WebTorrent's official destroy method with proper cleanup
    const torrentPromises = Object.values(torrents).map(torrent => {
      return new Promise((resolve) => {
        console.log(`�️ Destroying torrent with WebTorrent API: ${torrent.name}`);
        
        // WebTorrent's official way to destroy torrent and clear its cache
        torrent.destroy({
          destroyStore: true  // This tells WebTorrent to delete stored data
        }, (err) => {
          if (err) {
            console.log(`⚠️ Error destroying ${torrent.name}:`, err.message);
          } else {
            console.log(`✅ Successfully destroyed ${torrent.name} with cache cleanup`);
          }
          destroyedTorrents++;
          resolve();
        });
      });
    });
    
    // Wait for all torrents to be destroyed
    Promise.all(torrentPromises).then(() => {
      // Clear our local torrents object
      Object.keys(torrents).forEach(key => delete torrents[key]);
      
      // Clear WebTorrent client's internal cache
      console.log('🧹 Clearing WebTorrent client cache...');
      
      // Remove all torrents from the client
      while (client.torrents.length > 0) {
        const torrent = client.torrents[0];
        console.log(`🗑️ Removing torrent from client: ${torrent.name || torrent.infoHash}`);
        client.remove(torrent, { destroyStore: true }, (err) => {
          if (err) console.log('Error removing torrent:', err.message);
        });
      }
      
      // Force garbage collection if available
      try {
        if (global.gc) {
          global.gc();
          console.log('🧹 Forced garbage collection');
        }
      } catch (e) {
        console.log('⚠️ Garbage collection not available');
      }
      
      console.log(`🧹 Cache cleared using WebTorrent API: ${destroyedTorrents} torrents destroyed`);
      console.log(`🧹 Total memory freed: ${formatBytes(freedFromTorrents)}`);
      
      res.json({
        message: 'Cache cleared using WebTorrent official API',
        destroyedTorrents: destroyedTorrents,
        freedFromTorrents: freedFromTorrents,
        freedFromTorrentsFormatted: formatBytes(freedFromTorrents),
        method: 'webtorrent-official-api',
        totalFreed: freedFromTorrents,
        totalFreedFormatted: formatBytes(freedFromTorrents)
      });
    }).catch((error) => {
      console.error('Error during torrent destruction:', error);
      res.status(500).json({ error: 'Failed to clear cache properly' });
    });
    
  } catch (error) {
    console.error('Error clearing cache:', error);
    res.status(500).json({ error: 'Failed to clear cache' });
  }
});

// Debug endpoint to check cache locations
app.get('/api/cache/debug', (req, res) => {
  try {
    const fs = require('fs');
    const os = require('os');
    
    const possibleCacheDirs = [
      path.join(os.tmpdir(), 'webtorrent'),
      path.join(os.tmpdir(), 'webtorrent-' + process.getuid()),
      path.join(os.homedir(), '.webtorrent'),
      path.join(os.homedir(), 'Library', 'Caches', 'webtorrent'),
      path.join(os.homedir(), 'Library', 'Application Support', 'webtorrent'),
      path.join(__dirname, 'uploads'),
      path.join(__dirname, '.webtorrent'),
      path.join(process.cwd(), '.webtorrent'),
      path.join(process.cwd(), 'node_modules', '.cache', 'webtorrent')
    ];
    
    const existingDirs = [];
    const dirContents = {};
    
    possibleCacheDirs.forEach(dir => {
      try {
        if (fs.existsSync(dir)) {
          existingDirs.push(dir);
          const files = fs.readdirSync(dir);
          const totalSize = files.reduce((size, file) => {
            try {
              const filePath = path.join(dir, file);
              const stats = fs.statSync(filePath);
              return size + (stats.isFile() ? stats.size : 0);
            } catch {
              return size;
            }
          }, 0);
          
          dirContents[dir] = {
            fileCount: files.length,
            totalSize: totalSize,
            totalSizeFormatted: formatBytes(totalSize),
            files: files.slice(0, 10) // Show first 10 files
          };
        }
      } catch (error) {
        console.log(`Error checking ${dir}:`, error.message);
      }
    });
    
    // Also check WebTorrent client info
    const clientInfo = {
      activeTorrents: Object.keys(torrents).length,
      clientTorrents: client.torrents.length,
      torrents: Object.values(torrents).map(t => ({
        name: t.name,
        infoHash: t.infoHash,
        downloaded: t.downloaded,
        progress: t.progress,
        path: t.path || 'no path',
        ready: t.ready
      }))
    };
    
    res.json({
      existingDirs,
      dirContents,
      clientInfo,
      processInfo: {
        cwd: process.cwd(),
        tmpdir: os.tmpdir(),
        homedir: os.homedir(),
        uid: process.getuid ? process.getuid() : 'N/A'
      }
    });
  } catch (error) {
    console.error('Error getting cache debug info:', error);
    res.status(500).json({ error: 'Failed to get debug info' });
  }
});

app.post('/api/cache/clear-old', (req, res) => {
  try {
    const { days = 7 } = req.body;
    const fs = require('fs');
    const os = require('os');
    
    const cacheDir = path.join(os.homedir(), '.webtorrent');
    const cutoffDate = new Date(Date.now() - (days * 24 * 60 * 60 * 1000));
    
    let deletedFiles = 0;
    let deletedSize = 0;
    
    const clearOldFiles = (dirPath) => {
      try {
        if (!fs.existsSync(dirPath)) return;
        
        const files = fs.readdirSync(dirPath);
        files.forEach(file => {
          const filePath = path.join(dirPath, file);
          const stats = fs.statSync(filePath);
          
          if (stats.isDirectory()) {
            clearOldFiles(filePath);
          } else if (stats.mtime < cutoffDate) {
            deletedSize += stats.size;
            deletedFiles++;
            fs.unlinkSync(filePath);
            console.log(`🗑️ Deleted old file: ${file} (${Math.floor((Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60 * 24))} days old)`);
          }
        });
      } catch (error) {
        console.log('Error clearing old files:', error.message);
      }
    };
    
    clearOldFiles(cacheDir);
    
    console.log(`🧹 Old cache cleared: ${deletedFiles} files older than ${days} days, ${formatBytes(deletedSize)} freed`);
    
    res.json({
      message: `Cleared files older than ${days} days`,
      deletedFiles: deletedFiles,
      deletedSize: deletedSize,
      deletedSizeFormatted: formatBytes(deletedSize),
      days: days
    });
  } catch (error) {
    console.error('Error clearing old cache:', error);
    res.status(500).json({ error: 'Failed to clear old cache' });
  }
});

function formatBytes(bytes, decimals = 2) {
  if (bytes === 0) return '0 Bytes';
  
  const k = 1024;
  const dm = decimals < 0 ? 0 : decimals;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
  
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  
  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

app.get('/api/torrents/:infoHash/files', (req, res) => {
  const torrent = torrents[req.params.infoHash];
  if (!torrent) return res.status(404).json({ error: 'Torrent not found' });
  
  // Check if torrent is ready
  if (!torrent.ready) {
    console.log('Torrent not ready yet, returning empty files array');
    return res.json({ files: [], ready: false, message: 'Torrent still loading...' });
  }
  
  console.log(`Torrent ${torrent.name} has ${torrent.files.length} files`);
  
  const files = torrent.files.map((file, index) => ({
    name: file.name,
    length: file.length,
    index: index,
    originalIndex: index,
    isVideo: /\.(mp4|webm|mkv|avi|mov|wmv|flv|m4v)$/i.test(file.name)
  }));
  
  res.json({ files, ready: true });
});

app.get('/api/torrents/:infoHash/status', (req, res) => {
  const torrent = torrents[req.params.infoHash];
  if (!torrent) return res.status(404).json({ error: 'Torrent not found' });
  
  res.json({
    name: torrent.name || 'Loading...',
    downloaded: torrent.downloaded,
    uploaded: torrent.uploaded,
    downloadSpeed: torrent.downloadSpeed,
    uploadSpeed: torrent.uploadSpeed,
    peers: torrent.numPeers,
    progress: torrent.progress,
    length: torrent.length,
    ready: torrent.ready
  });
});

// Enhanced stats endpoint for video player
app.get('/api/torrents/:infoHash/stats', (req, res) => {
  const torrent = torrents[req.params.infoHash];
  if (!torrent) return res.status(404).json({ error: 'Torrent not found' });
  
  res.json({
    peers: torrent.numPeers || 0,
    downloadSpeed: torrent.downloadSpeed || 0,
    uploadSpeed: 0, // FORCED: Always 0 for security
    progress: (torrent.progress * 100) || 0,
    downloaded: torrent.downloaded || 0,
    uploaded: 0,    // FORCED: Always 0 for security
    total: torrent.length || 0,
    isConnected: torrent.numPeers > 0,
    name: torrent.name || 'Loading...',
    ready: torrent.ready || false,
    timeRemaining: torrent.timeRemaining || 0,
    ratio: 0,       // FORCED: Always 0 for security
    // Additional streaming stats
    pieces: {
      total: torrent.pieces ? torrent.pieces.length : 0,
      downloaded: torrent.pieces ? torrent.pieces.filter(piece => piece).length : 0
    },
    // Wire stats for connections (upload speeds forced to 0)
    wires: torrent.wires ? torrent.wires.map(wire => ({
      peerId: wire.peerId ? wire.peerId.toString('hex').substring(0, 8) : 'unknown',
      downloaded: wire.downloaded,
      uploaded: 0,           // FORCED: Always 0 for security
      downloadSpeed: wire.downloadSpeed || 0,
      uploadSpeed: 0         // FORCED: Always 0 for security
    })) : [],
    // SECURITY FLAGS
    downloadOnly: true,
    isSeeding: false,
    uploadBlocked: true
  });
});

// Optimized streaming endpoint for instant playback
app.get('/api/torrents/:infoHash/files/:fileIdx/stream', (req, res) => {
  const torrent = torrents[req.params.infoHash];
  if (!torrent) return res.status(404).json({ error: 'Torrent not found' });
  
  const file = torrent.files[req.params.fileIdx];
  if (!file) return res.status(404).json({ error: 'File not found' });
  
  // Resume torrent and ensure this file is selected for streaming
  torrent.resume();
  
  // Select the requested file for streaming with high priority
  file.select();
  
  // CRITICAL: Set streaming priority for instant playback
  // Prioritize the first 10% of the file for immediate streaming
  const prioritySize = Math.min(file.length * 0.1, 50 * 1024 * 1024); // 10% or 50MB max
  const priorityPieces = Math.ceil(prioritySize / torrent.pieceLength);
  
  // Calculate which pieces this file spans
  const firstPiece = Math.floor(file.offset / torrent.pieceLength);
  const lastPiece = Math.floor((file.offset + file.length - 1) / torrent.pieceLength);
  
  // Prioritize beginning pieces for instant streaming
  for (let i = firstPiece; i < Math.min(firstPiece + priorityPieces, lastPiece + 1); i++) {
    torrent.select(i, i, true); // High priority for beginning pieces
  }
  
  console.log(`🎬 INSTANT STREAMING: ${file.name} (${(file.length / 1024 / 1024).toFixed(1)} MB)`);
  console.log(`📊 Prioritizing pieces ${firstPiece}-${firstPiece + priorityPieces - 1} for instant playback`);
  
  const range = req.headers.range;
  
  if (!range) {
    // No range request, stream the whole file
    res.set({
      'Content-Type': getContentType(file.name),
      'Content-Length': file.length,
      'Accept-Ranges': 'bytes',
      'Cache-Control': 'no-cache',
      'Access-Control-Allow-Origin': '*'
    });
    
    const stream = file.createReadStream();
    
    // Add error handling for stream interruptions
    stream.on('error', (err) => {
      console.log(`Stream error for ${file.name}:`, err.message);
      if (!res.headersSent) {
        res.status(500).end();
      }
    });
    
    res.on('close', () => {
      console.log(`Client disconnected while streaming ${file.name}`);
      stream.destroy();
    });
    
    stream.pipe(res).on('error', (err) => {
      console.log(`Pipe error for ${file.name}:`, err.message);
    });
  } else {
    // Handle range requests for video seeking
    const parts = range.replace(/bytes=/, '').split('-');
    const start = parseInt(parts[0], 10);
    const end = parts[1] ? parseInt(parts[1], 10) : file.length - 1;
    const chunkSize = (end - start) + 1;
    
    res.writeHead(206, {
      'Content-Range': `bytes ${start}-${end}/${file.length}`,
      'Accept-Ranges': 'bytes',
      'Content-Length': chunkSize,
      'Content-Type': getContentType(file.name),
      'Cache-Control': 'no-cache',
      'Access-Control-Allow-Origin': '*'
    });
    
    const stream = file.createReadStream({ start, end });
    
    // Add error handling for range stream interruptions
    stream.on('error', (err) => {
      console.log(`Range stream error for ${file.name}:`, err.message);
      if (!res.headersSent) {
        res.status(500).end();
      }
    });
    
    res.on('close', () => {
      console.log(`Client disconnected during range request for ${file.name}`);
      stream.destroy();
    });
    
    stream.pipe(res).on('error', (err) => {
      console.log(`Range pipe error for ${file.name}:`, err.message);
    });
  }
});

// Download endpoint
app.get('/api/torrents/:infoHash/files/:fileIdx/download', (req, res) => {
  const torrent = torrents[req.params.infoHash];
  if (!torrent) return res.status(404).json({ error: 'Torrent not found' });
  
  const file = torrent.files[req.params.fileIdx];
  if (!file) return res.status(404).json({ error: 'File not found' });
  
  console.log(`📥 Download requested: ${file.name}`);
  
  res.set({
    'Content-Disposition': `attachment; filename="${file.name}"`,
    'Content-Type': 'application/octet-stream',
    'Content-Length': file.length,
    'Access-Control-Allow-Origin': '*'
  });
  
  const stream = file.createReadStream();
  
  // Add error handling for download stream interruptions
  stream.on('error', (err) => {
    console.log(`Download stream error for ${file.name}:`, err.message);
    if (!res.headersSent) {
      res.status(500).end();
    }
  });
  
  res.on('close', () => {
    console.log(`Client disconnected during download of ${file.name}`);
    stream.destroy();
  });
  
  stream.pipe(res).on('error', (err) => {
    console.log(`Download pipe error for ${file.name}:`, err.message);
  });
});

function getContentType(filename) {
  const ext = path.extname(filename).toLowerCase();
  const mimeTypes = {
    '.mp4': 'video/mp4',
    '.webm': 'video/webm',
    '.mkv': 'video/x-matroska',
    '.avi': 'video/x-msvideo',
    '.mov': 'video/quicktime',
    '.wmv': 'video/x-ms-wmv',
    '.flv': 'video/x-flv',
    '.m4v': 'video/x-m4v'
  };
  return mimeTypes[ext] || 'application/octet-stream';
}

const PORT = config.server.port;
const HOST = config.server.host;

app.listen(PORT, HOST, async () => {
  const serverUrl = `${config.server.protocol}://${HOST}:${PORT}`;
  console.log(`🌱 Seedbox Lite server running on ${serverUrl}`);
  console.log(`📱 Frontend URL: ${config.frontend.url}`);
  console.log('📁 Frontend will be served from /client/dist when built');
  console.log('🔗 API available at /api/*');
  console.log('🌪️ Real torrent functionality active - WebTorrent');
  console.log('⚠️  SECURITY: Download-only mode - Zero uploads guaranteed');
  
  if (config.isDevelopment) {
    console.log('🔧 Development mode - Environment variables loaded');
  }
  
  // Restore torrents from previous session
  console.log('🔄 Checking for previous torrent sessions...');
  await restoreTorrentsState();
  
  // Periodic state saving (every 5 minutes)
  setInterval(() => {
    if (Object.keys(torrents).length > 0) {
      saveTorrentsState();
    }
  }, 5 * 60 * 1000); // 5 minutes
});
