import { Request, Response, NextFunction } from 'express';
import path from 'path';
import { PutObjectCommand } from '@aws-sdk/client-s3';
import { s3Client, BUCKET_NAME } from '../utils/s3';
import prisma from '../utils/db';

export class EcosystemController {
  public listOfferings = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const user = (req as any).user;
      const isAdmin = user?.role === 'ADMIN';

      const offerings = await prisma.ecosystemOffering.findMany({
        where: isAdmin ? undefined : { isActive: true },
        orderBy: { orderIndex: 'asc' }
      });

      res.status(200).json(offerings);
    } catch (err) {
      next(err);
    }
  };

  public createOffering = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const data = req.body;
      const created = await prisma.ecosystemOffering.create({
        data: {
          name: data.name,
          type: data.type,
          tagline: data.tagline,
          description: data.description,
          benefits: data.benefits || [],
          websiteUrl: data.websiteUrl,
          ctaText: data.ctaText || 'Visit Website',
          logoIcon: data.logoIcon || 'Globe',
          logoUrl: data.logoUrl || null,
          mediaUrl: data.mediaUrl || null,
          mediaType: data.mediaType || null,
          orderIndex: data.orderIndex !== undefined ? data.orderIndex : 0,
          isActive: data.isActive !== undefined ? data.isActive : true,
        }
      });
      res.status(201).json(created);
    } catch (err) {
      next(err);
    }
  };

  public updateOffering = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { id } = req.params;
      const data = req.body;

      const updated = await prisma.ecosystemOffering.update({
        where: { id },
        data: {
          name: data.name,
          type: data.type,
          tagline: data.tagline,
          description: data.description,
          benefits: data.benefits,
          websiteUrl: data.websiteUrl,
          ctaText: data.ctaText,
          logoIcon: data.logoIcon,
          logoUrl: data.logoUrl,
          mediaUrl: data.mediaUrl,
          mediaType: data.mediaType,
          orderIndex: data.orderIndex,
          isActive: data.isActive,
        }
      });

      res.status(200).json(updated);
    } catch (err) {
      next(err);
    }
  };

  public deleteOffering = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { id } = req.params;
      await prisma.ecosystemOffering.delete({
        where: { id }
      });
      res.status(200).json({ message: 'Offering deleted successfully' });
    } catch (err) {
      next(err);
    }
  };

  public uploadFile = async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!req.file) {
        return res.status(400).json({ error: 'No file uploaded' });
      }

      const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
      const filename = uniqueSuffix + path.extname(req.file.originalname);

      await s3Client.send(new PutObjectCommand({
        Bucket: BUCKET_NAME,
        Key: filename,
        Body: req.file.buffer,
        ContentType: req.file.mimetype,
      }));

      const fileUrl = `/uploads/${filename}`;
      res.status(200).json({ url: fileUrl });
    } catch (err) {
      next(err);
    }
  };

  // ── Content Showcase (YouTube Videos) ──

  public listShowcaseContent = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const user = (req as any).user;
      const isAdmin = user?.role === 'ADMIN';

      const items = await prisma.contentShowcase.findMany({
        where: isAdmin ? undefined : { isActive: true },
        orderBy: { orderIndex: 'asc' }
      });

      res.status(200).json(items);
    } catch (err) {
      next(err);
    }
  };

  public createShowcaseContent = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const data = req.body;

      // Auto-extract YouTube thumbnail if not provided
      let thumbnailUrl = data.thumbnailUrl || null;
      if (!thumbnailUrl && data.youtubeUrl) {
        const videoId = this.extractYouTubeVideoId(data.youtubeUrl);
        if (videoId) {
          thumbnailUrl = `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`;
        }
      }

      const created = await prisma.contentShowcase.create({
        data: {
          title: data.title,
          description: data.description || null,
          youtubeUrl: data.youtubeUrl,
          thumbnailUrl,
          redirectUrl: data.redirectUrl || null,
          redirectLabel: data.redirectLabel || 'Learn More',
          orderIndex: data.orderIndex !== undefined ? data.orderIndex : 0,
          isActive: data.isActive !== undefined ? data.isActive : true,
        }
      });

      res.status(201).json(created);
    } catch (err) {
      next(err);
    }
  };

  public updateShowcaseContent = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { id } = req.params;
      const data = req.body;

      // Auto-extract YouTube thumbnail if URL changed and no explicit thumbnail
      let thumbnailUrl = data.thumbnailUrl;
      if (thumbnailUrl === undefined && data.youtubeUrl) {
        const videoId = this.extractYouTubeVideoId(data.youtubeUrl);
        if (videoId) {
          thumbnailUrl = `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`;
        }
      }

      const updated = await prisma.contentShowcase.update({
        where: { id },
        data: {
          title: data.title,
          description: data.description,
          youtubeUrl: data.youtubeUrl,
          thumbnailUrl,
          redirectUrl: data.redirectUrl,
          redirectLabel: data.redirectLabel,
          orderIndex: data.orderIndex,
          isActive: data.isActive,
        }
      });

      res.status(200).json(updated);
    } catch (err) {
      next(err);
    }
  };

  public deleteShowcaseContent = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { id } = req.params;
      await prisma.contentShowcase.delete({
        where: { id }
      });
      res.status(200).json({ message: 'Content deleted successfully' });
    } catch (err) {
      next(err);
    }
  };

  // Helper: Extract video ID from various YouTube URL formats
  private extractYouTubeVideoId(url: string): string | null {
    const patterns = [
      /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/shorts\/)([a-zA-Z0-9_-]{11})/,
      /(?:youtube-nocookie\.com\/embed\/)([a-zA-Z0-9_-]{11})/,
    ];
    for (const pattern of patterns) {
      const match = url.match(pattern);
      if (match) return match[1];
    }
    return null;
  }

  private extractJsonFromHtml(html: string, targetStr: string): any {
    const idx = html.indexOf(targetStr);
    if (idx === -1) return null;

    const start = idx + targetStr.length;
    let openBraces = 0;
    let inString = false;
    let escape = false;
    let endIdx = -1;

    for (let i = start; i < html.length; i++) {
      const char = html[i];
      if (escape) {
        escape = false;
        continue;
      }
      if (char === '\\') {
        escape = true;
        continue;
      }
      if (char === '"') {
        inString = !inString;
        continue;
      }
      if (!inString) {
        if (char === '{') {
          openBraces++;
        } else if (char === '}') {
          openBraces--;
          if (openBraces === 0) {
            endIdx = i + 1;
            break;
          }
        }
      }
    }

    if (endIdx !== -1) {
      try {
        const jsonStr = html.slice(start, endIdx);
        return JSON.parse(jsonStr);
      } catch (err) {
        console.error('Failed to parse extracted JSON:', err);
      }
    }
    return null;
  }

  public getYoutubeMeta = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { url } = req.query;
      if (!url || typeof url !== 'string') {
        return res.status(400).json({ error: 'URL parameter is required' });
      }

      const normUrl = url.trim();
      const lowerUrl = normUrl.toLowerCase();

      // Case 1: Twitter / X
      if (lowerUrl.includes('twitter.com') || lowerUrl.includes('x.com')) {
        const oembedUrl = `https://publish.twitter.com/oembed?url=${encodeURIComponent(normUrl)}`;
        try {
          const resOembed = await fetch(oembedUrl);
          if (resOembed.ok) {
            const data = await resOembed.json() as any;
            let description = '';
            if (data.html) {
              const pMatch = data.html.match(/<p[^>]*>([\s\S]*?)<\/p>/i);
              if (pMatch) {
                description = pMatch[1].replace(/<[^>]*>/g, '').trim();
              }
            }
            return res.status(200).json({
              title: data.author_name ? `Tweet by ${data.author_name}` : 'Tweet Content',
              description,
              thumbnailUrl: null
            });
          }
        } catch (err) {
          console.error('Twitter oEmbed fetch error:', err);
        }
        return res.status(200).json({
          title: 'Tweet Post',
          description: '',
          thumbnailUrl: null
        });
      }

      // Case 2: Instagram
      if (lowerUrl.includes('instagram.com')) {
        // Since Instagram requires Facebook API, return defaults so user can input manually
        return res.status(200).json({
          title: 'Instagram Post/Reel',
          description: '',
          thumbnailUrl: null
        });
      }

      // Case 3: YouTube
      const videoId = this.extractYouTubeVideoId(normUrl);
      if (!videoId) {
        return res.status(400).json({ error: 'Invalid YouTube, Instagram, or Twitter/X URL' });
      }

      // 1. Fetch from oEmbed (gives us a clean title and thumbnail immediately)
      const oembedUrl = `https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=${videoId}&format=json`;
      let title = '';
      let thumbnailUrl = `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`;
      
      try {
        const oembedRes = await fetch(oembedUrl);
        if (oembedRes.ok) {
          const data = await oembedRes.json() as any;
          title = data.title || '';
          thumbnailUrl = data.thumbnail_url || thumbnailUrl;
        }
      } catch (err) {
        console.error('oEmbed fetch error:', err);
      }

      // 2. Fetch raw page to extract the full description
      let description = '';
      try {
        const watchUrl = `https://www.youtube.com/watch?v=${videoId}`;
        const pageRes = await fetch(watchUrl, {
          headers: {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
            'Accept-Language': 'en-US,en;q=0.9'
          }
        });
        if (pageRes.ok) {
          const html = await pageRes.text();

          // Try to extract from ytInitialPlayerResponse first (full description)
          const playerResponse = this.extractJsonFromHtml(html, 'ytInitialPlayerResponse = ');
          if (playerResponse && playerResponse.videoDetails) {
            description = playerResponse.videoDetails.shortDescription || '';
            if (playerResponse.videoDetails.title && !title) {
              title = playerResponse.videoDetails.title;
            }
          }

          // Fallback to meta tags if description is still empty
          if (!description) {
            const descMatch = html.match(/<meta\s+property="og:description"\s+content="([^"]*)"/i) ||
                              html.match(/<meta\s+name="description"\s+content="([^"]*)"/i) ||
                              html.match(/<meta\s+content="([^"]*)"\s+property="og:description"/i) ||
                              html.match(/<meta\s+content="([^"]*)"\s+name="description"/i);
            if (descMatch && descMatch[1]) {
              description = descMatch[1]
                .replace(/&quot;/g, '"')
                .replace(/&amp;/g, '&')
                .replace(/&lt;/g, '<')
                .replace(/&gt;/g, '>')
                .replace(/&#39;/g, "'")
                .replace(/&apos;/g, "'");
            }
          }
        }
      } catch (err) {
        console.error('HTML scrape error:', err);
      }

      res.status(200).json({
        title,
        description,
        thumbnailUrl
      });
    } catch (err) {
      next(err);
    }
  };
}
