import express, { type Request, Response, NextFunction } from "express";
import compression from "compression";
import { registerRoutes, findVideoByAnyId } from "./routes";
import { videoSyncService } from "./videoSync";
import { setupVite, serveStatic, log } from "./vite";
import { storage } from "./storage";
import fs from "fs";
import path from "path";

const app = express();

// Enable gzip compression for faster responses
app.use(compression());

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

// Performance and caching middleware
app.use((req, res, next) => {
  // Set no-cache headers only for HTML pages to prevent blank screen issues
  if (req.path === '/' || req.path.endsWith('.html') || !req.path.includes('.')) {
    res.set({
      'Cache-Control': 'no-cache, no-store, must-revalidate',
      'Pragma': 'no-cache',
      'Expires': '0'
    });
  } 
  // Cache static assets for better performance
  else if (req.path.includes('/assets/') || req.path.match(/\.(js|css|png|jpg|jpeg|gif|ico|svg)$/)) {
    res.set({
      'Cache-Control': 'public, max-age=31536000', // 1 year
      'ETag': `"${Date.now()}"` // Simple ETag
    });
  }
  // Cache API responses for 30 seconds
  else if (req.path.startsWith('/api/videos') && req.method === 'GET') {
    res.set({
      'Cache-Control': 'public, max-age=30',
      'ETag': `"videos-${Date.now()}"`
    });
  }
  next();
});

app.use((req, res, next) => {
  const start = Date.now();
  const path = req.path;
  let capturedJsonResponse: Record<string, any> | undefined = undefined;

  const originalResJson = res.json;
  res.json = function (bodyJson, ...args) {
    capturedJsonResponse = bodyJson;
    return originalResJson.apply(res, [bodyJson, ...args]);
  };

  res.on("finish", () => {
    const duration = Date.now() - start;
    if (path.startsWith("/api")) {
      let logLine = `${req.method} ${path} ${res.statusCode} in ${duration}ms`;
      if (capturedJsonResponse) {
        logLine += ` :: ${JSON.stringify(capturedJsonResponse)}`;
      }

      if (logLine.length > 80) {
        logLine = logLine.slice(0, 79) + "…";
      }

      log(logLine);
    }
  });

  next();
});

(async () => {
  // Initialize video sync service for automatic Bunny.net updates
  await videoSyncService.initialize();
  
  // Social media prerendering middleware - samo za social bot-e
  app.get('/video/:videoId', async (req, res, next) => {
    const { videoId } = req.params;
    const userAgent = req.get('User-Agent') || '';
    
    // Če je to Facebook, Twitter, WhatsApp ali podoben scraper
    const isSocialBot = /facebookexternalhit|twitterbot|whatsapp|telegrambot|discordbot|slackbot|linkedinbot|viber/i.test(userAgent);
    
    // Če NI social bot, pustimo da React routing prevzame
    if (!isSocialBot) {
      return next();
    }
    
    if (isSocialBot) {
      try {
        console.log(`🤖 Social bot detected: ${userAgent}, looking for video: ${videoId}`);
        // Use the same findVideoByAnyId function as in routes
        const video = await findVideoByAnyId(videoId);
        
        if (!video) {
          console.log(`❌ Video not found for social bot: ${videoId}`);
          return next(); // Če video ne obstaja, preusmerimo na običajno SPA
        }
        
        console.log(`✅ Video found for social bot: ${video.title}`);
        console.log(`📷 Original thumbnail: ${video.thumbnailUrl}`);

        // Preberemo osnovni HTML template
        const clientTemplate = path.resolve(import.meta.dirname, "..", "client", "index.html");
        let template = await fs.promises.readFile(clientTemplate, "utf-8");
        
        // Escape special characters v naslovih in opisih
        const escapeHtml = (text: string) => text.replace(/"/g, '&quot;').replace(/'/g, '&#39;');
        
        // Zamenimo meta oznake z video specifičnimi
        const baseUrl = req.protocol + '://' + req.get('host');
        // Use short ID for sharing URLs
        const shortId = video.id.replace(/-/g, '').substring(0, 8);
        const videoUrl = `${baseUrl}/video/${shortId}`;
        // Optimize thumbnail for social media sharing - larger size and JPEG format
        let thumbnailUrl = video.thumbnailUrl;
        if (thumbnailUrl) {
          // Replace small WebP with larger JPEG for better social media compatibility
          thumbnailUrl = thumbnailUrl
            .replace('width=400&height=225', 'width=1200&height=630')
            .replace('format=webp', 'format=jpg');
        } else {
          thumbnailUrl = `${baseUrl}/api/video-thumbnail/${video.id}`;
        }
        
        // Zamenjamo osnovne meta oznake
        template = template.replace(
          /<title>.*<\/title>/,
          `<title>${escapeHtml(video.title)} | go4.video</title>`
        );
        
        template = template.replace(
          /<meta name="description" content="[^"]*"/,
          `<meta name="description" content="${escapeHtml(video.description || `Watch ${video.title} on go4.video`)}"`
        );
        
        // Zamenjamo Open Graph meta oznake
        template = template.replace(
          /<meta property="og:title" content="[^"]*"/,
          `<meta property="og:title" content="${escapeHtml(video.title)}"`
        );
        
        // Truncate description to 150 characters for clean social preview
        let shortDescription = video.description || `${video.title} – Jetzt ansehen auf video.folx.tv`;
        if (shortDescription.length > 150) {
          shortDescription = shortDescription.substring(0, 147) + '...';
        }
        template = template.replace(
          /<meta property="og:description" content="[^"]*"/,
          `<meta property="og:description" content="${escapeHtml(shortDescription)}"`
        );
        
        // Replace og:image - handle both with and without id attribute
        template = template.replace(
          /<meta property="og:image"[^>]*>/,
          `<meta property="og:image" id="og-image" content="${thumbnailUrl}">`
        );
        
        // Replace og:image:type to match JPG format
        template = template.replace(
          /<meta property="og:image:type" content="[^"]*"/,
          `<meta property="og:image:type" content="image/jpeg"`
        );
        
        // Replace Twitter image - handle both with and without id attribute  
        template = template.replace(
          /<meta name="twitter:image"[^>]*>/,
          `<meta name="twitter:image" id="twitter-image" content="${thumbnailUrl}">`
        );
        
        template = template.replace(
          /<meta name="twitter:title" content="[^"]*"/,
          `<meta name="twitter:title" content="${escapeHtml(video.title)}"`
        );
        
        template = template.replace(
          /<meta name="twitter:description" content="[^"]*"/,
          `<meta name="twitter:description" content="${escapeHtml(shortDescription)}"`
        );
        
        // Also update URL and secure image tags that have id attributes
        template = template.replace(
          /<meta property="og:url"[^>]*>/,
          `<meta property="og:url" id="og-url" content="${videoUrl}">`
        );
        
        template = template.replace(
          /<meta property="og:image:secure_url"[^>]*>/,
          `<meta property="og:image:secure_url" id="og-image-secure" content="${thumbnailUrl}">`
        );

        // Dodamo dodatne OG oznake za video z detajlnimi informacijami
        const duration = Math.floor(video.duration / 60) + ':' + (video.duration % 60).toString().padStart(2, '0');
        const additionalMeta = `
    <meta property="og:type" content="video.other">
    <meta property="og:video:duration" content="${video.duration}">
    <meta property="video:duration" content="${video.duration}">
    <meta property="video:release_date" content="${video.createdAt?.toISOString()}">
    
    <!-- Dodatni Twitter Card meta podatki -->
    <meta name="twitter:player:width" content="1200">
    <meta name="twitter:player:height" content="630">
    <meta name="twitter:creator" content="@folaborable">
    
    <!-- Structured data for Google -->
    <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "VideoObject",
      "name": "${escapeHtml(video.title)}",
      "description": "${escapeHtml(shortDescription)}",
      "thumbnailUrl": "${thumbnailUrl}",
      "uploadDate": "${video.createdAt?.toISOString()}",
      "duration": "PT${Math.floor(video.duration / 60)}M${video.duration % 60}S",
      "contentUrl": "${video.videoUrl}",
      "embedUrl": "${videoUrl}",
      "interactionStatistic": {
        "@type": "InteractionCounter",
        "interactionType": "https://schema.org/WatchAction",
        "userInteractionCount": ${video.views || 0}
      },
      "publisher": {
        "@type": "Organization",
        "name": "FOLX.TV",
        "logo": {
          "@type": "ImageObject",
          "url": "https://video.folx.tv/folx-logo.png"
        },
        "url": "https://video.folx.tv"
      },
      "potentialAction": {
        "@type": "WatchAction",
        "target": "${videoUrl}"
      }
    }
    </script>`;
        
        template = template.replace('</head>', `${additionalMeta}\n</head>`);
        
        res.setHeader('Content-Type', 'text/html');
        res.send(template);
        return;
        
      } catch (error) {
        console.error('Error rendering video page for social bot:', error);
        // If an error occurs, continue with normal SPA
        return next();
      }
    }
    
    // For regular users, continue with SPA
    next();
  });
  
  const server = await registerRoutes(app);

  app.use((err: any, _req: Request, res: Response, _next: NextFunction) => {
    const status = err.status || err.statusCode || 500;
    const message = err.message || "Internal Server Error";

    res.status(status).json({ message });
    throw err;
  });

  // importantly only setup vite in development and after
  // setting up all the other routes so the catch-all route
  // doesn't interfere with the other routes
  if (app.get("env") === "development") {
    await setupVite(app, server);
  } else {
    serveStatic(app);
  }

  // ALWAYS serve the app on the port specified in the environment variable PORT
  // Other ports are firewalled. Default to 5000 if not specified.
  // this serves both the API and the client.
  // It is the only port that is not firewalled.
  const port = parseInt(process.env.PORT || '5000', 10);
  server.listen({
    port,
    host: "0.0.0.0",
    reusePort: true,
  }, () => {
    log(`serving on port ${port}`);
  });
})();
