import type { Express, Request, Response } from "express";
import { createServer, type Server } from "http";
import express from "express";
import compression from "compression";
import { storage } from "./storage";
import { z } from "zod";
import { 
  updateVideoSchema, insertVideoSchema, insertUserSchema, 
  insertVideoUploadSchema, insertCategorySchema, insertTagSchema,
  type User, type VideoUpload 
} from "@shared/schema";
import multer from "multer";
import { randomUUID } from "crypto";
import path from "path";
import fs from "fs";
import session from "express-session";
import sharp from "sharp";
import fetch from "node-fetch";
import { setupAuth, isAuthenticated, isAdmin } from "./replitAuth";
import { ObjectStorageService, ObjectNotFoundError } from "./objectStorage";
import { generateVideoDescription, generateBulkDescriptions } from "./aiService";

// Find video by short or long ID - moved to top level for export
export async function findVideoByAnyId(id: string) {
  try {
    // If it's already a full UUID, use it directly
    if (id.length === 36 && id.includes('-')) {
      return await storage.getVideo(id);
    }
    
    // If it's an 8-character short ID, find by short ID
    if (id.length === 8) {
      const allVideos = await storage.getVideos(600, 0);
      return allVideos.find(v => v.id.replace(/-/g, '').substring(0, 8) === id);
    }
    
    return undefined;
  } catch (error) {
    console.error(`Error finding video by ID ${id}:`, error);
    return undefined;
  }
}

// Extend express session
declare module "express-session" {
  interface SessionData {
    userId: string;
  }
}

// Configure multer for video uploads
const upload = multer({
  storage: multer.diskStorage({
    destination: './uploads/videos',
    filename: (req, file, cb) => {
      const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
      cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
    }
  }),
  limits: {
    fileSize: 500 * 1024 * 1024, // 500MB max file size
  },
  fileFilter: (req, file, cb) => {
    // Allow video files only
    if (file.mimetype.startsWith('video/')) {
      cb(null, true);
    } else {
      cb(new Error('Only video files are allowed'));
    }
  }
});

// Simple session-based authentication middleware
const authenticate = (req: Request, res: Response, next: any) => {
  if (req.session?.userId) {
    next();
  } else {
    res.status(401).json({ message: "Authentication required" });
  }
};

export async function registerRoutes(app: Express): Promise<Server> {
  // Setup Replit Auth first
  await setupAuth(app);

  // Social media crawler detection middleware for /video/:id routes
  // This serves proper OG meta tags to crawlers while letting regular users get the SPA
  app.get('/video/:id', async (req, res, next) => {
    const userAgent = req.headers['user-agent']?.toLowerCase() || '';
    
    // List of social media crawler user agents
    const crawlers = [
      'facebookexternalhit',
      'facebot',
      'twitterbot',
      'whatsapp',
      'telegrambot',
      'linkedinbot',
      'pinterest',
      'slackbot',
      'viberbot',
      'discordbot',
      'applebot',
      'googlebot',
      'bingbot',
      'yandex',
      'baiduspider',
      'duckduckbot'
    ];
    
    const isCrawler = crawlers.some(crawler => userAgent.includes(crawler));
    
    if (!isCrawler) {
      // Not a crawler, let the SPA handle it
      return next();
    }
    
    try {
      const { id } = req.params;
      
      // Find video from cache
      const allVideos = await storage.getVideos(600, 0);
      let video;
      
      if (id.length === 36 && id.includes('-')) {
        video = allVideos.find(v => v.id === id);
      } else if (id.length === 8) {
        video = allVideos.find(v => v.id.replace(/-/g, '').substring(0, 8) === id);
      } else {
        video = allVideos.find(v => v.id.includes(id));
      }
      
      if (!video) {
        return next(); // Let SPA handle 404
      }

      const baseUrl = 'https://video.folx.tv';
      const videoUrl = `${baseUrl}/video/${video.id}`;
      
      // Get high-quality thumbnail for sharing (1200x630 is ideal for Facebook)
      let thumbnailUrl = `${baseUrl}/api/social-image`;
      if (video.thumbnailUrl) {
        thumbnailUrl = video.thumbnailUrl
          .replace(/width=\d+/gi, 'width=1200')
          .replace(/height=\d+/gi, 'height=630')
          .replace(/format=webp/gi, 'format=jpg');
      }
      
      // Clean description for meta tags
      const description = video.description 
        ? video.description.substring(0, 200).replace(/[<>"']/g, '') 
        : `Schauen Sie ${video.title} auf video.folx.tv - Die beste Musik`;
      
      const title = video.title || 'video.folx.tv';

      // Return HTML page with OG tags for crawlers
      const html = `<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${title} - video.folx.tv</title>
  
  <!-- Open Graph meta tags for Facebook/Social Media -->
  <meta property="og:type" content="video.other">
  <meta property="og:title" content="${title}">
  <meta property="og:description" content="${description}">
  <meta property="og:image" content="${thumbnailUrl}">
  <meta property="og:image:secure_url" content="${thumbnailUrl}">
  <meta property="og:image:width" content="1200">
  <meta property="og:image:height" content="630">
  <meta property="og:image:type" content="image/jpeg">
  <meta property="og:url" content="${videoUrl}">
  <meta property="og:site_name" content="video.folx.tv">
  <meta property="og:locale" content="de_DE">
  
  <!-- Twitter Card meta tags -->
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:title" content="${title}">
  <meta name="twitter:description" content="${description}">
  <meta name="twitter:image" content="${thumbnailUrl}">
  
  <link rel="canonical" href="${videoUrl}">
</head>
<body>
  <h1>${title}</h1>
  <p>${description}</p>
  <p><a href="${videoUrl}">Watch on video.folx.tv</a></p>
</body>
</html>`;

      res.set('Content-Type', 'text/html');
      res.send(html);
    } catch (error) {
      console.error('Error generating OG tags for crawler:', error);
      next(); // Let SPA handle errors
    }
  });

  // Add compression middleware for better performance
  app.use(compression({
    level: 6,
    threshold: 1024, // Only compress responses larger than 1KB
    filter: (req: any, res: any) => {
      // Don't compress video files
      if (req.headers['accept']?.includes('video/')) {
        return false;
      }
      return compression.filter(req, res);
    }
  }));

  // Configure session middleware
  app.use(session({
    secret: process.env.SESSION_SECRET || 'dev-secret-key',
    resave: false,
    saveUninitialized: false,
    cookie: { secure: false, maxAge: 24 * 60 * 60 * 1000 } // 24 hours
  }));

  // Authentication Routes
  app.post("/api/auth/register", async (req, res) => {
    try {
      const userData = insertUserSchema.parse(req.body);
      
      // Check if user already exists
      const existingUser = await storage.getUserByEmail(userData.email);
      if (existingUser) {
        return res.status(400).json({ message: "User already exists with this email" });
      }

      const user = await storage.createUser(userData);
      
      // Remove password from response
      const { passwordHash, ...userResponse } = user;
      res.status(201).json(userResponse);
    } catch (error) {
      if (error instanceof z.ZodError) {
        return res.status(400).json({ message: "Invalid user data", errors: error.errors });
      }
      res.status(500).json({ message: "Failed to create user" });
    }
  });

  app.post("/api/auth/login", async (req, res) => {
    try {
      const { email, password } = req.body;
      
      if (!email || !password) {
        return res.status(400).json({ message: "Email and password are required" });
      }

      const user = await storage.validateUserPassword(email, password);
      if (!user) {
        return res.status(401).json({ message: "Invalid credentials" });
      }

      // Set session
      req.session.userId = user.id;
      
      // Remove password from response
      const { passwordHash, ...userResponse } = user;
      res.json(userResponse);
    } catch (error) {
      res.status(500).json({ message: "Failed to login" });
    }
  });

  app.post("/api/auth/logout", (req, res) => {
    req.session?.destroy(() => {
      res.json({ message: "Logged out successfully" });
    });
  });

  // Sitemap.xml for SEO
  app.get("/sitemap.xml", async (req, res) => {
    try {
      const baseUrl = "https://video.folx.tv";
      const videos = await storage.getVideos(1000, 0);
      
      // Helper to escape XML special characters
      const escapeXml = (str: string) => {
        if (!str) return '';
        return str
          .replace(/&/g, '&amp;')
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/"/g, '&quot;')
          .replace(/'/g, '&apos;');
      };
      
      let xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
  <url>
    <loc>${baseUrl}/</loc>
    <changefreq>daily</changefreq>
    <priority>1.0</priority>
  </url>
`;

      for (const video of videos) {
        const shortId = video.id.replace(/-/g, '').substring(0, 8);
        const lastmod = video.createdAt ? new Date(video.createdAt).toISOString().split('T')[0] : new Date().toISOString().split('T')[0];
        const safeTitle = escapeXml(video.title);
        const safeDescription = escapeXml(video.description || video.title);
        const safeThumbnail = escapeXml(video.thumbnailUrl || '');
        
        xml += `  <url>
    <loc>${baseUrl}/video/${shortId}</loc>
    <lastmod>${lastmod}</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
    <video:video>
      <video:thumbnail_loc>${safeThumbnail}</video:thumbnail_loc>
      <video:title>${safeTitle}</video:title>
      <video:description>${safeDescription}</video:description>
      <video:duration>${video.duration || 0}</video:duration>
    </video:video>
  </url>
`;
      }

      xml += `</urlset>`;

      res.setHeader('Content-Type', 'application/xml');
      res.setHeader('Cache-Control', 'public, max-age=3600');
      res.send(xml);
    } catch (error) {
      console.error('Error generating sitemap:', error);
      res.status(500).send('Error generating sitemap');
    }
  });

  // Robots.txt
  app.get("/robots.txt", (req, res) => {
    const baseUrl = "https://video.folx.tv";
    const robots = `User-agent: *
Allow: /
Disallow: /admin
Disallow: /api/

Sitemap: ${baseUrl}/sitemap.xml
`;
    res.setHeader('Content-Type', 'text/plain');
    res.send(robots);
  });

  app.get("/api/auth/me", authenticate, async (req, res) => {
    try {
      const user = await storage.getUser(req.session.userId!);
      if (!user) {
        return res.status(404).json({ message: "User not found" });
      }
      
      const { passwordHash, ...userResponse } = user;
      res.json(userResponse);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch user" });
    }
  });

  // Video Routes
  // Bunny.net administration routes
  app.get("/api/bunny/stats", async (req, res) => {
    try {
      const videos = await storage.getVideos(1, 1000);
      const totalViews = videos.length > 0 ? videos.reduce((sum: number, video: any) => sum + video.views, 0) : 0;
      
      const stats = {
        totalVideos: videos.length,
        totalViews,
        totalStorage: 0, // Would need separate Bunny API call
        bandwidth: 0 // Would need separate Bunny API call
      };
      
      res.json(stats);
    } catch (error) {
      console.error("Error fetching Bunny stats:", error);
      res.status(500).json({ message: "Failed to fetch statistics" });
    }
  });

  app.delete("/api/bunny/videos/:id", async (req, res) => {
    try {
      const { id } = req.params;
      
      // Note: This would need implementation in BunnyService
      // For now, return success (deletion would happen in Bunny dashboard)
      res.json({ message: "Video deletion initiated" });
    } catch (error) {
      console.error("Error deleting video:", error);
      res.status(500).json({ message: "Failed to delete video" });
    }
  });

  // Manual sync endpoint to force refresh from Bunny.net
  app.post("/api/bunny/sync", async (req, res) => {
    try {
      console.log('🔄 Manual video sync requested...');
      // Import videoSyncService to trigger manual sync
      const { videoSyncService } = await import('./videoSync');
      await videoSyncService.initialize();
      
      const videos = await storage.getVideos(1, 1000);
      res.json({ 
        message: "Video sync completed successfully",
        totalVideos: videos.length,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error("Error during manual sync:", error);
      res.status(500).json({ message: "Failed to sync videos from Bunny.net" });
    }
  });



  app.get("/api/videos", async (req, res) => {
    try {
      const limit = parseInt(req.query.limit as string) || 20;
      const offset = parseInt(req.query.offset as string) || 0;
      const search = req.query.search as string;

      // Skip search for queries shorter than 2 characters for performance
      const searchQuery = search && search.length >= 2 ? search : undefined;

      // Create cache key for ETag
      const cacheKey = `videos-${limit}-${offset}-${searchQuery || 'all'}`;
      const etag = `"${cacheKey}"`;
      
      // Check if client has cached version
      if (req.headers['if-none-match'] === etag) {
        return res.status(304).end();
      }

      // Set optimized cache headers
      res.set({
        'Cache-Control': 'public, max-age=120, stale-while-revalidate=300', // 2 min cache, 5 min stale
        'ETag': etag,
        'X-Content-Type-Options': 'nosniff',
        'Vary': 'Accept-Encoding'
      });

      console.log(`Fetching videos: limit=${limit}, offset=${offset}, search=${searchQuery}`);
      
      const videos = await storage.getVideos(limit, offset, searchQuery);
      const total = await storage.getVideoCount(searchQuery);
      
      console.log(`Returning ${videos.length} videos`);
      
      res.json({
        videos,
        total,
        hasMore: offset + limit < total
      });
    } catch (error) {
      console.error("Error fetching videos:", error);
      res.status(500).json({ message: "Failed to fetch videos" });
    }
  });

  // Face detection endpoint for thumbnails
  app.post("/api/videos/:id/analyze-face", async (req, res) => {
    try {
      const { id } = req.params;
      const video = await storage.getVideo(id);
      
      if (!video) {
        return res.status(404).json({ message: "Video not found" });
      }
      
      if (!video.thumbnailUrl) {
        return res.status(400).json({ message: "Video has no thumbnail" });
      }
      
      // Import smart thumbnail service (no external dependencies)
      const { smartThumbnailService } = await import("./smart-thumbnail-service");
      const result = await smartThumbnailService.getOptimizedThumbnailInfo(video.thumbnailUrl);
      
      // Update video with face position data
      await storage.updateVideo(id, {
        faceCenterPosition: result.faceCenterPosition,
        facesDetected: result.facesDetected,
        faceConfidence: result.confidence
      });
      
      res.json({
        videoId: id,
        ...result
      });
    } catch (error) {
      console.error("Error analyzing face in thumbnail:", error);
      res.status(500).json({ message: "Failed to analyze face" });
    }
  });

  // Batch face analysis for all videos
  app.post("/api/videos/batch-analyze-faces", async (req, res) => {
    try {
      // Get all videos that don't have face analysis yet
      const allVideos = await storage.getVideos(1000, 0); // Get up to 1000 videos
      const videosToProcess = allVideos.filter(video => !video.faceCenterPosition && video.thumbnailUrl);
      
      if (videosToProcess.length === 0) {
        return res.json({
          message: "All videos already processed or no thumbnails available",
          processed: 0,
          total: allVideos.length
        });
      }

      console.log(`Starting batch face analysis for ${videosToProcess.length} videos...`);
      
      // Import smart thumbnail service (no external dependencies)
      const { smartThumbnailService } = await import("./smart-thumbnail-service");
      let processed = 0;
      let failed = 0;
      
      // Process videos in batches to avoid overwhelming the system
      const batchSize = 5;
      for (let i = 0; i < videosToProcess.length; i += batchSize) {
        const batch = videosToProcess.slice(i, i + batchSize);
        
        await Promise.all(batch.map(async (video) => {
          try {
            console.log(`Processing face detection for video: ${video.title} (${video.id})`);
            const result = await smartThumbnailService.getOptimizedThumbnailInfo(video.thumbnailUrl);
            
            await storage.updateVideo(video.id, {
              faceCenterPosition: result.faceCenterPosition,
              facesDetected: result.facesDetected,
              faceConfidence: result.confidence
            });
            
            processed++;
            console.log(`✅ Face analysis completed for ${video.title} - Faces detected: ${result.facesDetected}`);
          } catch (error) {
            console.error(`❌ Face analysis failed for ${video.title}:`, error);
            failed++;
          }
        }));
        
        // Small delay between batches to be respectful
        if (i + batchSize < videosToProcess.length) {
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }
      
      console.log(`Batch face analysis completed: ${processed} processed, ${failed} failed`);
      
      res.json({
        message: "Batch face analysis completed",
        processed,
        failed,
        total: videosToProcess.length
      });
    } catch (error) {
      console.error("Error in batch face analysis:", error);
      res.status(500).json({ message: "Failed to perform batch face analysis" });
    }
  });

  // Generate short ID from long UUID
  function generateShortId(longId: string): string {
    // Take first 8 characters and remove dashes for shorter, cleaner URLs
    return longId.replace(/-/g, '').substring(0, 8);
  }


  // Get single video by ID (supports both short and long IDs)
  app.get("/api/videos/:id", async (req, res) => {
    try {
      const video = await findVideoByAnyId(req.params.id);
      if (!video) {
        return res.status(404).json({ message: "Video not found" });
      }
      res.json(video);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch video" });
    }
  });

  // Get video ads/spots metadata from Bunny.net
  app.get("/api/videos/:id/ads", async (req, res) => {
    try {
      const { id } = req.params;
      
      // Check if video exists first (supports short and long IDs)
      const video = await findVideoByAnyId(id);
      if (!video) {
        return res.status(404).json({ message: "Video not found" });
      }

      // Get ads from Bunny.net API
      let ads: any[] = [];
      try {
        const { BunnyService } = await import("./bunny");
        const bunnyService = new BunnyService();
        ads = await bunnyService.getVideoAds(video.id); // Use full ID for API calls
        console.log(`Retrieved ${ads.length} ad spots for video ${id}`);
      } catch (error) {
        console.error(`Failed to get ads from Bunny.net for video ${id}:`, error);
        // Return empty array if Bunny service fails
        ads = [];
      }
      
      res.json({
        videoId: id,
        ads: ads,
        totalAds: ads.length
      });
    } catch (error) {
      console.error(`Error fetching ads for video ${req.params.id}:`, error);
      res.status(500).json({ message: "Failed to fetch video ads" });
    }
  });

  // Update video views (supports short and long IDs)
  app.post("/api/videos/:id/view", async (req, res) => {
    try {
      const video = await findVideoByAnyId(req.params.id);
      if (!video) {
        return res.status(404).json({ message: "Video not found" });
      }
      
      // Use the full video ID for storage operations
      await storage.updateVideoViews(video.id);
      res.json({ success: true });
    } catch (error) {
      res.status(500).json({ message: "Failed to update views" });
    }
  });

  // Create new video
  app.post("/api/videos", authenticate, async (req, res) => {
    try {
      const videoData = insertVideoSchema.parse(req.body);
      const video = await storage.createVideo(videoData);
      res.status(201).json(video);
    } catch (error) {
      if (error instanceof z.ZodError) {
        return res.status(400).json({ message: "Invalid video data", errors: error.errors });
      }
      res.status(500).json({ message: "Failed to create video" });
    }
  });

  // Update video metadata (title, description, etc.)
  app.patch("/api/videos/:id", authenticate, async (req, res) => {
    try {
      const updates = updateVideoSchema.parse(req.body);
      const video = await storage.updateVideo(req.params.id, updates);
      
      if (!video) {
        return res.status(404).json({ message: "Video not found" });
      }
      
      res.json(video);
    } catch (error) {
      if (error instanceof z.ZodError) {
        return res.status(400).json({ message: "Invalid request data", errors: error.errors });
      }
      res.status(500).json({ message: "Failed to update video" });
    }
  });

  // Delete video
  app.delete("/api/videos/:id", authenticate, async (req, res) => {
    try {
      const success = await storage.deleteVideo(req.params.id);
      if (!success) {
        return res.status(404).json({ message: "Video not found" });
      }
      res.json({ success: true, message: "Video deleted successfully" });
    } catch (error) {
      res.status(500).json({ message: "Failed to delete video" });
    }
  });

  // Video Upload Routes
  app.post("/api/uploads/start", authenticate, async (req, res) => {
    try {
      const { originalFileName, fileSize, mimeType } = req.body;
      
      if (!originalFileName || !fileSize || !mimeType) {
        return res.status(400).json({ 
          message: "originalFileName, fileSize, and mimeType are required" 
        });
      }

      const uploadData = {
        userId: req.session.userId!,
        originalFileName,
        fileSize: parseInt(fileSize),
        mimeType,
        uploadStatus: "uploading" as const,
        uploadProgress: 0
      };

      const upload = await storage.createVideoUpload(uploadData);
      res.status(201).json(upload);
    } catch (error) {
      res.status(500).json({ message: "Failed to initialize upload" });
    }
  });

  app.post("/api/uploads/:id/video", authenticate, upload.single('video'), async (req, res) => {
    try {
      const uploadId = req.params.id;
      const file = req.file;
      
      if (!file) {
        return res.status(400).json({ message: "No video file provided" });
      }

      // Update upload with file information
      await storage.updateVideoUpload(uploadId, {
        uploadStatus: "processing",
        uploadProgress: 1.0
      });

      // Create video record
      const videoData = {
        title: req.body.title || path.parse(file.originalname).name,
        description: req.body.description || "",
        thumbnailUrl: req.body.thumbnailUrl || "https://via.placeholder.com/800x450",
        videoUrl: `/uploads/videos/${file.filename}`,
        duration: parseInt(req.body.duration) || 0,
        views: 0,
        category: req.body.category || "",
        tags: req.body.tags ? JSON.parse(req.body.tags) : [],
        isPublic: req.body.isPublic !== "false",
        uploadStatus: "completed",
        originalFileName: file.originalname,
        fileSize: file.size,
        format: path.extname(file.originalname).slice(1)
      };

      const video = await storage.createVideo(videoData);

      // Link video to upload
      await storage.updateVideoUpload(uploadId, {
        videoId: video.id,
        uploadStatus: "completed"
      });

      res.json({ video, upload: { id: uploadId, status: "completed" } });
    } catch (error) {
      console.error("Upload error:", error);
      
      // Update upload status to failed
      if (req.params.id) {
        await storage.updateVideoUpload(req.params.id, {
          uploadStatus: "failed",
          errorMessage: error instanceof Error ? error.message : "Upload failed"
        });
      }
      
      res.status(500).json({ message: "Failed to upload video" });
    }
  });

  app.get("/api/uploads/:id/status", authenticate, async (req, res) => {
    try {
      const upload = await storage.getVideoUpload(req.params.id);
      if (!upload) {
        return res.status(404).json({ message: "Upload not found" });
      }
      res.json(upload);
    } catch (error) {
      res.status(500).json({ message: "Failed to get upload status" });
    }
  });

  app.get("/api/uploads/user", authenticate, async (req, res) => {
    try {
      const uploads = await storage.getUserVideoUploads(req.session.userId!);
      res.json(uploads);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch user uploads" });
    }
  });

  // Category Routes
  app.get("/api/categories", async (req, res) => {
    try {
      const categories = await storage.getCategories();
      res.json(categories);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch categories" });
    }
  });

  app.post("/api/categories", authenticate, async (req, res) => {
    try {
      const categoryData = insertCategorySchema.parse(req.body);
      const category = await storage.createCategory(categoryData);
      res.status(201).json(category);
    } catch (error) {
      if (error instanceof z.ZodError) {
        return res.status(400).json({ message: "Invalid category data", errors: error.errors });
      }
      res.status(500).json({ message: "Failed to create category" });
    }
  });

  app.patch("/api/categories/:id", authenticate, async (req, res) => {
    try {
      const updates = insertCategorySchema.partial().parse(req.body);
      const category = await storage.updateCategory(req.params.id, updates);
      
      if (!category) {
        return res.status(404).json({ message: "Category not found" });
      }
      
      res.json(category);
    } catch (error) {
      if (error instanceof z.ZodError) {
        return res.status(400).json({ message: "Invalid category data", errors: error.errors });
      }
      res.status(500).json({ message: "Failed to update category" });
    }
  });

  app.delete("/api/categories/:id", authenticate, async (req, res) => {
    try {
      const success = await storage.deleteCategory(req.params.id);
      if (!success) {
        return res.status(404).json({ message: "Category not found" });
      }
      res.json({ success: true, message: "Category deleted successfully" });
    } catch (error) {
      res.status(500).json({ message: "Failed to delete category" });
    }
  });

  // Tag Routes
  app.get("/api/tags", async (req, res) => {
    try {
      const limit = parseInt(req.query.limit as string) || 50;
      const popular = req.query.popular === "true";
      
      const tags = popular 
        ? await storage.getPopularTags(limit)
        : await storage.getTags();
        
      res.json(tags);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch tags" });
    }
  });

  app.post("/api/tags", authenticate, async (req, res) => {
    try {
      const tagData = insertTagSchema.parse(req.body);
      const tag = await storage.createTag(tagData);
      res.status(201).json(tag);
    } catch (error) {
      if (error instanceof z.ZodError) {
        return res.status(400).json({ message: "Invalid tag data", errors: error.errors });
      }
      res.status(500).json({ message: "Failed to create tag" });
    }
  });

  // Serve uploaded videos
  app.use('/uploads', express.static('uploads'));





  // Serve ads.txt file specifically
  app.get("/ads.txt", (req, res) => {
    res.type("text/plain");
    res.sendFile(path.join(__dirname, "../client/public/ads.txt"));
  });

  // Open Graph image generation endpoint
  app.get('/api/og-image', (req, res) => {
    try {
      // Generate SVG-based image for Open Graph
      const svg = `<svg width="1200" height="630" xmlns="http://www.w3.org/2000/svg">
        <defs>
          <linearGradient id="bgGradient" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" style="stop-color:hsl(250, 50%, 15%);stop-opacity:1" />
            <stop offset="100%" style="stop-color:hsl(240, 30%, 25%);stop-opacity:1" />
          </linearGradient>
          <linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" style="stop-color:#6366f1;stop-opacity:1" />
            <stop offset="100%" style="stop-color:#8b5cf6;stop-opacity:1" />
          </linearGradient>
        </defs>
        
        <rect width="1200" height="630" fill="url(#bgGradient)"/>
        
        <polygon points="100,100 180,180 70,180" fill="#6366f1" opacity="0.1"/>
        <polygon points="1000,200 1120,280 880,280" fill="#8b5cf6" opacity="0.08"/>
        <polygon points="200,450 260,510 140,510" fill="#6366f1" opacity="0.12"/>
        <polygon points="950,500 1040,590 860,590" fill="#8b5cf6" opacity="0.06"/>
        
        <rect x="300" y="250" width="60" height="60" rx="15" fill="url(#logoGradient)"/>
        
        <polygon points="321,265 321,295 342,280" fill="white"/>
        
        <text x="400" y="330" font-family="Arial, sans-serif" font-size="72" font-weight="bold" fill="white">FOLX.TV</text>
        
        <text x="400" y="380" font-family="Arial, sans-serif" font-size="32" fill="rgba(255,255,255,0.8)">Professional Video Streaming Platform</text>
        
        <text x="400" y="430" font-family="Arial, sans-serif" font-size="24" fill="rgba(255,255,255,0.6)">Geschichte des Liedes • FOLX STADL • Premium Content</text>
      </svg>`;

      res.setHeader('Content-Type', 'image/svg+xml');
      res.setHeader('Cache-Control', 'public, max-age=86400'); // Cache for 24 hours
      res.send(svg);
    } catch (error) {
      console.error('Error generating OG image:', error);
      res.status(500).send('Error generating image');
    }
  });

  // Custom social image endpoint - directly serve the beautiful triangular image
  app.get('/api/social-image', async (req, res) => {
    try {
      console.log('📸 Generating beautiful social image...');
      
      // Create the beautiful triangular design directly
      const width = 1200;
      const height = 630;
      
      const svg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
        <defs>
          <linearGradient id="bgGradient" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" style="stop-color:#da234d;stop-opacity:1" />
            <stop offset="25%" style="stop-color:#c51d47;stop-opacity:1" />
            <stop offset="50%" style="stop-color:#b01640;stop-opacity:1" />
            <stop offset="75%" style="stop-color:#9b0f39;stop-opacity:1" />
            <stop offset="100%" style="stop-color:#860832;stop-opacity:1" />
          </linearGradient>
        </defs>
        
        <!-- Beautiful gradient background -->
        <rect width="${width}" height="${height}" fill="url(#bgGradient)"/>
        
        <!-- Large triangular geometric patterns -->
        <polygon points="0,0 400,0 200,200" fill="#ffffff" opacity="0.08"/>
        <polygon points="800,0 1200,0 1000,300" fill="#ffffff" opacity="0.06"/>
        <polygon points="0,400 300,630 0,630" fill="#ffffff" opacity="0.1"/>
        <polygon points="900,330 1200,630 900,630" fill="#ffffff" opacity="0.07"/>
        <polygon points="400,200 600,400 200,400" fill="#ffffff" opacity="0.05"/>
        <polygon points="600,0 1000,0 800,200" fill="#ffffff" opacity="0.04"/>
        
        <!-- Central sparkle element -->
        <polygon points="1150,480 1170,500 1150,520 1130,500" fill="#ffffff" opacity="0.9"/>
        
        <!-- Main title centered -->
        <text x="600" y="300" font-family="Arial, sans-serif" font-size="88" font-weight="bold" fill="white" text-anchor="middle">FOLX.TV</text>
        <text x="600" y="380" font-family="Arial, sans-serif" font-size="36" fill="rgba(255,255,255,0.9)" text-anchor="middle">video.folx.tv</text>
        <text x="600" y="430" font-family="Arial, sans-serif" font-size="24" fill="rgba(255,255,255,0.7)" text-anchor="middle">Amazing Content • Premium Streaming Platform</text>
      </svg>`;

      const buffer = await sharp(Buffer.from(svg))
        .png({ quality: 95, compressionLevel: 6, progressive: true })
        .toBuffer();

      console.log(`📸 Beautiful social image generated: ${buffer.length} bytes`);
      
      // Set aggressive cache-busting headers for social media platforms
      res.set({
        'Content-Type': 'image/png',
        'Content-Length': buffer.length.toString(),
        'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0',
        'Pragma': 'no-cache',
        'Expires': '0',
        'Last-Modified': new Date().toUTCString(),
        'ETag': `W/"${buffer.length}-${Date.now()}"`,
        'Access-Control-Allow-Origin': '*',
        'Vary': 'User-Agent'
      });
      res.send(buffer);
      
    } catch (error) {
      console.error('❌ Error generating social image:', error);
      res.status(500).send('Error generating social image');
    }
  });

  // Favicon generation endpoint
  app.get('/api/favicon', async (req, res) => {
    try {
      const size = req.query.size ? parseInt(req.query.size as string) : 32;
      const format = req.query.format as string || 'svg';
      const padding = Math.max(2, size * 0.1);
      const logoSize = size - (padding * 2);
      const cornerRadius = Math.max(2, size * 0.15);
      
      if (format === 'png') {
        // Ustvarimo PNG ikono za iOS PWA
        // Ustvarimo SVG za pretvorbo v PNG
        const svg = `<svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
          <defs>
            <linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="100%">
              <stop offset="0%" style="stop-color:#da234d;stop-opacity:1" />
              <stop offset="100%" style="stop-color:#da234d;stop-opacity:1" />
            </linearGradient>
          </defs>
          
          <!-- iOS stil ozadje z rounded corners -->
          <rect x="0" y="0" width="${size}" height="${size}" rx="${cornerRadius * 1.5}" fill="url(#logoGradient)"/>
          
          <!-- Večji bel play triangle v središču ikone -->
          <polygon points="${size * 0.38},${size * 0.32} ${size * 0.38},${size * 0.68} ${size * 0.68},${size * 0.5}" fill="white" opacity="1.0"/>
        </svg>`;

        // Pretvorimo SVG v PNG z Sharp
        const pngBuffer = await sharp(Buffer.from(svg))
          .png({ quality: 100, compressionLevel: 0 })
          .toBuffer();

        res.setHeader('Content-Type', 'image/png');
        res.setHeader('Cache-Control', 'public, max-age=86400'); // Cache for 24 hours
        res.send(pngBuffer);
      } else {
        // Originalni SVG favicon
        const svg = `<svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
          <defs>
            <linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="100%">
              <stop offset="0%" style="stop-color:#da234d;stop-opacity:1" />
              <stop offset="100%" style="stop-color:#da234d;stop-opacity:1" />
            </linearGradient>
          </defs>
          
          <!-- Logo background -->
          <rect x="${padding}" y="${padding}" width="${logoSize}" height="${logoSize}" rx="${cornerRadius}" fill="url(#logoGradient)"/>
          
          <!-- Večji play triangle v središču -->
          <polygon points="${size * 0.38},${size * 0.32} ${size * 0.38},${size * 0.68} ${size * 0.68},${size * 0.5}" fill="white"/>
        </svg>`;

        res.setHeader('Content-Type', 'image/svg+xml');
        res.setHeader('Cache-Control', 'public, max-age=86400'); // Cache for 24 hours
        res.send(svg);
      }
    } catch (error) {
      console.error('Error generating favicon:', error);
      res.status(500).send('Error generating favicon');
    }
  });

  // Social media thumbnail generation endpoint
  app.get('/api/video-thumbnail/:videoId', async (req, res) => {
    try {
      const { videoId } = req.params;
      const video = await storage.getVideo(videoId);
      
      if (!video) {
        console.log(`❌ Video not found: ${videoId}`);
        return res.status(404).send('Video not found');
      }

      console.log(`🖼️ Generating thumbnail for: ${video.title}`);

      // Uporabimo čisti thumbnail iz Bunny.net - prioriteta
      if (video.thumbnailUrl) {
        try {
          console.log(`📥 Fetching thumbnail from Bunny.net: ${video.thumbnailUrl}`);
          const response = await fetch(video.thumbnailUrl);
          if (response.ok) {
            const thumbnailBuffer = await response.arrayBuffer();
            
            // Optimiziramo thumbnail za social media brez overlay-a
            const resizedBuffer = await sharp(Buffer.from(thumbnailBuffer))
              .resize(1200, 630, { fit: 'cover', position: 'center' })
              .jpeg({ quality: 85, progressive: true }) // JPEG je bolje za photo thumbnails
              .toBuffer();

            console.log(`✅ Real thumbnail processed: ${resizedBuffer.length} bytes`);
            
            res.setHeader('Content-Type', 'image/jpeg');
            res.setHeader('Cache-Control', 'public, max-age=7200'); // Cache za 2 uri
            res.setHeader('Access-Control-Allow-Origin', '*');
            return res.send(resizedBuffer);
          }
        } catch (fetchError) {
          console.log('⚠️ Failed to fetch real thumbnail, falling back to generated:', fetchError);
        }
      }

      // Fallback: ustvarimo generirani thumbnail z video informacijami
      const width = 1200;
      const height = 630; // Facebook/Twitter optimalne dimenzije
      
      const svg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
        <defs>
          <linearGradient id="bgGradient" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" style="stop-color:#2D1B69;stop-opacity:1" />
            <stop offset="50%" style="stop-color:#6366f1;stop-opacity:1" />
            <stop offset="100%" style="stop-color:#8b5cf6;stop-opacity:1" />
          </linearGradient>
          <linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" style="stop-color:#ffffff;stop-opacity:0.9" />
            <stop offset="100%" style="stop-color:#ffffff;stop-opacity:0.7" />
          </linearGradient>
        </defs>
        
        <!-- Ozadje -->
        <rect width="${width}" height="${height}" fill="url(#bgGradient)"/>
        
        <!-- Dekorativni elementi -->
        <polygon points="100,100 180,180 70,180" fill="#ffffff" opacity="0.1"/>
        <polygon points="1000,200 1120,280 880,280" fill="#ffffff" opacity="0.08"/>
        <polygon points="200,450 260,510 140,510" fill="#ffffff" opacity="0.12"/>
        <polygon points="950,500 1040,590 860,590" fill="#ffffff" opacity="0.06"/>
        
        <!-- Glavni play button v levi strani -->
        <circle cx="300" cy="315" r="80" fill="url(#logoGradient)" opacity="0.9"/>
        <polygon points="270,285 270,345 330,315" fill="#6366f1"/>
        
        <!-- Video naslov -->
        <text x="450" y="250" font-family="Arial, sans-serif" font-size="42" font-weight="bold" fill="white" text-anchor="start">${video.title.length > 35 ? video.title.substring(0, 32) + '...' : video.title}</text>
        
        <!-- Video opis -->
        <text x="450" y="300" font-family="Arial, sans-serif" font-size="24" fill="rgba(255,255,255,0.8)" text-anchor="start">${video.description && video.description.length > 60 ? video.description.substring(0, 57) + '...' : video.description || 'Watch this video on video.folx.tv'}</text>
        
        <!-- go4.video logo -->
        <text x="450" y="400" font-family="Arial, sans-serif" font-size="32" font-weight="bold" fill="white" text-anchor="start">FOLX.TV</text>
        <text x="450" y="430" font-family="Arial, sans-serif" font-size="18" fill="rgba(255,255,255,0.7)" text-anchor="start">Professional Video Streaming Platform</text>
        
        <!-- Video dolžina -->
        <rect x="950" y="500" width="200" height="40" rx="20" fill="rgba(0,0,0,0.7)"/>
        <text x="1050" y="525" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="white" text-anchor="middle">${Math.floor(video.duration / 60)}:${(video.duration % 60).toString().padStart(2, '0')}</text>
      </svg>`;

      // Pretvorimo SVG v PNG
      const pngBuffer = await sharp(Buffer.from(svg))
        .png({ quality: 90, compressionLevel: 6 })
        .toBuffer();

      res.setHeader('Content-Type', 'image/png');
      res.setHeader('Cache-Control', 'public, max-age=3600'); // Cache za 1 uro
      res.send(pngBuffer);
      
    } catch (error) {
      console.error('Error generating video thumbnail:', error);
      res.status(500).send('Error generating thumbnail');
    }
  });

  // ===== ADMIN ROUTES =====
  
  // Auth route to get current user
  app.get('/api/auth/user', isAuthenticated, async (req: any, res) => {
    try {
      // Import the generateDeterministicUUID function from replitAuth
      const { createHash } = await import('crypto');
      const generateDeterministicUUID = (replitId: string): string => {
        const hash = createHash('sha256').update(`replit_${replitId}`).digest('hex');
        return [
          hash.substring(0, 8),
          hash.substring(8, 12),
          '4' + hash.substring(13, 16),
          (parseInt(hash.substring(16, 17), 16) & 0x3 | 0x8).toString(16) + hash.substring(17, 20),
          hash.substring(20, 32)
        ].join('-');
      };
      
      const userId = generateDeterministicUUID(req.user.claims.sub);
      const user = await storage.getUser(userId);
      if (!user) {
        return res.status(404).json({ message: "User not found" });
      }
      
      // Remove sensitive data
      const { passwordHash, ...userResponse } = user;
      res.json(userResponse);
    } catch (error) {
      console.error("Error fetching user:", error);
      res.status(500).json({ message: "Failed to fetch user" });
    }
  });

  // Admin video management
  app.get('/api/admin/videos', isAdmin, async (req, res) => {
    try {
      const limit = parseInt(req.query.limit as string) || 500; // Increased default limit for admin
      const offset = parseInt(req.query.offset as string) || 0;
      const search = req.query.search as string;
      
      const videos = await storage.getVideos(limit, offset, search);
      const total = await storage.getVideoCount(search);
      
      res.json({ videos, total, limit, offset });
    } catch (error) {
      console.error("Error fetching admin videos:", error);
      res.status(500).json({ message: "Failed to fetch videos" });
    }
  });

  app.patch('/api/admin/videos/:id', isAdmin, async (req, res) => {
    try {
      const videoId = req.params.id;
      console.log(`PATCH request for video ${videoId} with body:`, JSON.stringify(req.body, null, 2));
      const updateData = updateVideoSchema.parse(req.body);
      console.log(`Parsed update data:`, JSON.stringify(updateData, null, 2));
      
      const updatedVideo = await storage.updateVideo(videoId, updateData);
      if (!updatedVideo) {
        return res.status(404).json({ message: "Video not found" });
      }
      
      res.json(updatedVideo);
    } catch (error) {
      console.error("Error updating video:", error);
      if (error instanceof z.ZodError) {
        res.status(400).json({ message: "Invalid video data", errors: error.errors });
      } else {
        res.status(500).json({ message: "Failed to update video" });
      }
    }
  });

  // Thumbnail upload
  app.post('/api/admin/thumbnails/upload', isAdmin, async (req, res) => {
    try {
      const objectStorageService = new ObjectStorageService();
      const uploadURL = await objectStorageService.getThumbnailUploadURL();
      res.json({ uploadURL });
    } catch (error) {
      console.error("Error getting thumbnail upload URL:", error);
      res.status(500).json({ message: "Failed to get upload URL" });
    }
  });

  // Serve uploaded objects
  app.get("/objects/:objectPath(*)", async (req, res) => {
    const objectStorageService = new ObjectStorageService();
    try {
      const objectFile = await objectStorageService.getObjectFile(req.path);
      objectStorageService.downloadObject(objectFile, res);
    } catch (error) {
      console.error("Error serving object:", error);
      if (error instanceof ObjectNotFoundError) {
        return res.sendStatus(404);
      }
      return res.sendStatus(500);
    }
  });

  // ===== USER MANAGEMENT ROUTES (ADMIN) =====

  // Get all users (admin only)
  app.get('/api/admin/users', isAdmin, async (req, res) => {
    try {
      const limit = parseInt(req.query.limit as string) || 50;
      const offset = parseInt(req.query.offset as string) || 0;
      const search = req.query.search as string;
      
      // For now, get all users - in production you'd want pagination
      const users = await storage.getAllUsers ? await storage.getAllUsers(limit, offset, search) : [];
      
      // Remove password hashes from response
      const safeUsers = users.map(({ passwordHash, ...user }) => user);
      
      res.json({ 
        users: safeUsers, 
        total: users.length,
        limit, 
        offset 
      });
    } catch (error) {
      console.error("Error fetching users:", error);
      res.status(500).json({ message: "Failed to fetch users" });
    }
  });

  // Get user by ID (admin only)
  app.get('/api/admin/users/:id', isAdmin, async (req, res) => {
    try {
      const user = await storage.getUser(req.params.id);
      if (!user) {
        return res.status(404).json({ message: "User not found" });
      }
      
      // Remove password hash from response
      const { passwordHash, ...safeUser } = user;
      res.json(safeUser);
    } catch (error) {
      console.error("Error fetching user:", error);
      res.status(500).json({ message: "Failed to fetch user" });
    }
  });

  // Update user admin status (super admin only)
  app.patch('/api/admin/users/:id/admin', isAuthenticated, async (req: any, res) => {
    try {
      const currentUserId = `replit_${req.user.claims.sub}`;
      const currentUser = await storage.getUser(currentUserId);
      
      if (!currentUser?.isSuperAdmin) {
        return res.status(403).json({ message: "Super admin access required" });
      }

      const userId = req.params.id;
      const { isAdmin } = req.body;
      
      const updatedUser = await storage.updateUser(userId, { isAdmin });
      if (!updatedUser) {
        return res.status(404).json({ message: "User not found" });
      }
      
      // Remove password hash from response
      const { passwordHash, ...safeUser } = updatedUser;
      res.json(safeUser);
    } catch (error) {
      console.error("Error updating user admin status:", error);
      res.status(500).json({ message: "Failed to update user" });
    }
  });

  // Update user active status (admin only)
  app.patch('/api/admin/users/:id/status', isAdmin, async (req, res) => {
    try {
      const userId = req.params.id;
      const { isActive } = req.body;
      
      if (typeof isActive !== 'boolean') {
        return res.status(400).json({ message: "isActive must be a boolean" });
      }
      
      const updatedUser = await storage.updateUser(userId, { isActive });
      if (!updatedUser) {
        return res.status(404).json({ message: "User not found" });
      }
      
      // Remove password hash from response
      const { passwordHash, ...safeUser } = updatedUser;
      res.json(safeUser);
    } catch (error) {
      console.error("Error updating user status:", error);
      res.status(500).json({ message: "Failed to update user status" });
    }
  });

  // Get admin statistics (admin only)
  app.get('/api/admin/stats', isAdmin, async (req, res) => {
    try {
      const videoCount = await storage.getVideoCount();
      const userCount = await storage.getUserCount ? await storage.getUserCount() : 0;
      
      // Get recent videos
      const recentVideos = await storage.getVideos(5, 0);
      
      // Basic stats - in production you might want more sophisticated analytics
      const stats = {
        videos: {
          total: videoCount,
          recent: recentVideos.length
        },
        users: {
          total: userCount,
          // Could add more user analytics here
        },
        platform: {
          uptime: process.uptime(),
          nodeVersion: process.version
        }
      };
      
      res.json(stats);
    } catch (error) {
      console.error("Error fetching admin stats:", error);
      res.status(500).json({ message: "Failed to fetch statistics" });
    }
  });

  // ===== AI DESCRIPTION ROUTES =====

  // Generate AI description for single video (admin only)
  app.post('/api/admin/videos/:id/generate-description', isAdmin, async (req, res) => {
    try {
      const videoId = req.params.id;
      const { maxCharacters = 500, includeArtistInfo = true, includeLabelInfo = true, customInstructions } = req.body;
      
      console.log("AI description request for video:", videoId); // Debug log
      
      // Get video details
      const video = await storage.getVideo(videoId);
      if (!video) {
        console.log("Video not found:", videoId); // Debug log
        return res.status(404).json({ message: "Video not found" });
      }
      
      console.log("Generating AI description for title:", video.title); // Debug log
      
      // Generate description using AI
      const description = await generateVideoDescription(video.title, {
        maxCharacters,
        language: "german",
        includeArtistInfo,
        includeLabelInfo,
        customInstructions,
        contentType: video.contentType || 'music_video'
      });
      
      console.log("Generated description:", description); // Debug log
      
      const result = { 
        description,
        title: video.title,
        characterCount: description.length,
        maxCharacters
      };
      
      console.log("Sending AI response:", result); // Debug log
      res.json(result);
      
    } catch (error) {
      console.error("Error generating AI description:", error);
      res.status(500).json({ 
        message: error instanceof Error ? error.message : "Failed to generate description" 
      });
    }
  });

  // Generate AI descriptions for multiple videos (admin only)
  app.post('/api/admin/videos/generate-descriptions-bulk', isAdmin, async (req, res) => {
    try {
      const { videoIds, maxCharacters = 500, includeArtistInfo = true, includeLabelInfo = true } = req.body;
      
      if (!Array.isArray(videoIds) || videoIds.length === 0) {
        return res.status(400).json({ message: "Video IDs array is required" });
      }
      
      if (videoIds.length > 50) {
        return res.status(400).json({ message: "Maximum 50 videos can be processed at once" });
      }
      
      // Get video details for all requested videos
      const videos = [];
      for (const id of videoIds) {
        const video = await storage.getVideo(id);
        if (video) {
          videos.push({ id: video.id, title: video.title });
        }
      }
      
      // Generate descriptions using AI
      const results = await generateBulkDescriptions(videos, {
        maxCharacters,
        language: "slovenian", 
        includeArtistInfo,
        includeLabelInfo
      });
      
      res.json({
        results,
        processed: results.length,
        successful: results.filter(r => !r.error).length,
        failed: results.filter(r => r.error).length
      });
      
    } catch (error) {
      console.error("Error generating bulk AI descriptions:", error);
      res.status(500).json({ 
        message: error instanceof Error ? error.message : "Failed to generate descriptions" 
      });
    }
  });

  // Facebook/Social Media Share Page - Returns HTML with proper OG tags for video sharing
  app.get('/share/video/:id', async (req, res) => {
    try {
      const { id } = req.params;
      
      // Find video from cache (not direct Bunny API to avoid 404 errors)
      const allVideos = await storage.getVideos(600, 0);
      let video;
      
      // Check if it's a full UUID or short ID
      if (id.length === 36 && id.includes('-')) {
        video = allVideos.find(v => v.id === id);
      } else if (id.length === 8) {
        video = allVideos.find(v => v.id.replace(/-/g, '').substring(0, 8) === id);
      } else {
        video = allVideos.find(v => v.id.includes(id));
      }
      
      if (!video) {
        return res.status(404).send('Video not found');
      }

      const baseUrl = 'https://video.folx.tv';
      const videoUrl = `${baseUrl}/video/${video.id}`;
      
      // Get high-quality thumbnail for sharing (1200x630 is ideal for Facebook)
      let thumbnailUrl = `${baseUrl}/api/social-image`;
      if (video.thumbnailUrl) {
        thumbnailUrl = video.thumbnailUrl
          .replace(/width=\d+/gi, 'width=1200')
          .replace(/height=\d+/gi, 'height=630')
          .replace(/format=webp/gi, 'format=jpg');
      }
      
      // Clean description for meta tags
      const description = video.description 
        ? video.description.substring(0, 200).replace(/[<>"']/g, '') 
        : `Jetzt ${video.title} auf video.folx.tv ansehen - Die beste Volksmusik`;
      
      const title = video.title || 'video.folx.tv';

      // Return HTML page with OG tags that redirects to actual video
      const html = `<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${title} - video.folx.tv</title>
  
  <!-- Open Graph meta tags for Facebook -->
  <meta property="og:type" content="video.other">
  <meta property="og:title" content="${title}">
  <meta property="og:description" content="${description}">
  <meta property="og:image" content="${thumbnailUrl}">
  <meta property="og:image:secure_url" content="${thumbnailUrl}">
  <meta property="og:image:width" content="1200">
  <meta property="og:image:height" content="630">
  <meta property="og:image:type" content="image/jpeg">
  <meta property="og:url" content="${videoUrl}">
  <meta property="og:site_name" content="video.folx.tv">
  <meta property="og:locale" content="de_DE">
  
  <!-- Twitter Card meta tags -->
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:title" content="${title}">
  <meta name="twitter:description" content="${description}">
  <meta name="twitter:image" content="${thumbnailUrl}">
  
  <!-- Redirect to actual video page for humans -->
  <meta http-equiv="refresh" content="0;url=${videoUrl}">
  <link rel="canonical" href="${videoUrl}">
  
  <style>
    body { 
      font-family: Arial, sans-serif; 
      background: #1a1a2e; 
      color: white; 
      display: flex; 
      align-items: center; 
      justify-content: center; 
      height: 100vh; 
      margin: 0; 
    }
    .container { text-align: center; }
    a { color: #da234d; text-decoration: none; }
  </style>
</head>
<body>
  <div class="container">
    <h1>Weiterleitung...</h1>
    <p>Falls keine automatische Weiterleitung erfolgt, <a href="${videoUrl}">hier klicken</a>.</p>
  </div>
  <script>window.location.href = "${videoUrl}";</script>
</body>
</html>`;

      res.set('Content-Type', 'text/html');
      res.send(html);
    } catch (error) {
      console.error('Error generating share page:', error);
      res.status(500).send('Error generating share page');
    }
  });

  // SEO - Sitemap XML with all video pages
  app.get('/sitemap.xml', async (req, res) => {
    try {
      const videos = await storage.getVideos(1, 1000); // Get all videos
      const baseUrl = 'https://video.folx.tv';
      
      let sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>${baseUrl}/</loc>
    <changefreq>daily</changefreq>
    <priority>1.0</priority>
    <lastmod>${new Date().toISOString().split('T')[0]}</lastmod>
  </url>`;

      // Add all video pages
      videos.forEach(video => {
        sitemap += `
  <url>
    <loc>${baseUrl}/video/${video.id}</loc>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
    <lastmod>${video.updatedAt ? video.updatedAt.toISOString().split('T')[0] : new Date().toISOString().split('T')[0]}</lastmod>
  </url>`;
      });

      sitemap += '\n</urlset>';

      res.set('Content-Type', 'application/xml');
      res.send(sitemap);
    } catch (error) {
      console.error('Error generating sitemap:', error);
      res.status(500).send('Error generating sitemap');
    }
  });

  const httpServer = createServer(app);
  return httpServer;
}
