const express = require('express');
const router = express.Router();
const axios = require('axios');
const { authenticate } = require('../middleware/auth');
const { readLimiter } = require('../middleware/rateLimiter');
const logger = require('../utils/logger');
const { getRadioStationMetadata } = require('../utils/radioMetadata');

/**
 * Fetch metadata from radio stream (ICY/Shoutcast metadata)
 * This attempts to extract "now playing" information from radio streams
 */
router.get('/radio/:channelId', readLimiter, authenticate, async (req, res) => {
  const { channelId } = req.params;
  const { db } = require('../database/db');

  try {
    // Validate channel ID
    const id = parseInt(channelId, 10);
    if (isNaN(id) || id < 1) {
      return res.status(400).json({ error: 'Invalid channel ID' });
    }

    // Get channel URL from database
    db.get(
      'SELECT url, name FROM channels WHERE id = ? AND is_radio = 1',
      [id],
      async (err, channel) => {
        if (err || !channel) {
          return res.status(404).json({ error: 'Channel not found' });
        }

        try {
          // Request stream with ICY metadata headers
          const response = await axios.get(channel.url, {
            headers: {
              'Icy-MetaData': '1',
              'User-Agent': 'StreamFlow/1.0'
            },
            responseType: 'stream',
            timeout: 5000,
            maxRedirects: 5
          });

          let metadata = {
            channelId: parseInt(channelId),
            channelName: channel.name,
            title: null,
            artist: null,
            song: null,
            streamTitle: null,
            bitrate: null,
            genre: null,
            url: null
          };

          // Extract ICY headers
          const icyName = response.headers['icy-name'];
          const icyGenre = response.headers['icy-genre'];
          const icyBr = response.headers['icy-br'];
          const icyUrl = response.headers['icy-url'];
          const icyDescription = response.headers['icy-description'];

          if (icyName) {
            // Filter out stream quality info (e.g., "europafm_aacp_48k")
            const cleanName = icyName.replace(/_aacp?_\d+k?/gi, '').replace(/_mp3_\d+k?/gi, '').replace(/_\d+k/gi, '');
            if (cleanName && !cleanName.match(/^\w+_\w+$/)) {
              metadata.streamTitle = cleanName;
            } else {
              metadata.streamTitle = icyName;
            }
          }
          if (icyGenre) metadata.genre = icyGenre;
          if (icyBr) metadata.bitrate = icyBr + ' kbps';
          if (icyUrl) metadata.url = icyUrl;

          // Try to get current track from ICY-MetaInt
          const metaInt = parseInt(response.headers['icy-metaint']);
          
          if (metaInt && metaInt > 0) {
            // Read metadata from stream
            const chunks = [];
            let bytesRead = 0;
            let metadataFound = false;

            response.data.on('data', (chunk) => {
              if (metadataFound) return;
              
              chunks.push(chunk);
              bytesRead += chunk.length;

              // Once we have enough data, parse metadata
              if (bytesRead >= metaInt + 255) {
                const buffer = Buffer.concat(chunks);
                const metadataLength = buffer[metaInt] * 16;
                
                if (metadataLength > 0) {
                  const metadataBuffer = buffer.slice(metaInt + 1, metaInt + 1 + metadataLength);
                  const metadataString = metadataBuffer.toString('utf8').replace(/\0/g, '');
                  
                  logger.info(`[Metadata] Raw metadata string for ${channel.name}: ${metadataString}`);
                  
                  // Parse StreamTitle='Artist - Song'
                  const titleMatch = metadataString.match(/StreamTitle='([^']*)'/);
                  if (titleMatch && titleMatch[1]) {
                    const rawTitle = titleMatch[1];
                    logger.info(`[Metadata] Raw title: ${rawTitle}`);
                    
                    // Skip if it's just stream quality info
                    if (!rawTitle.match(/^\w+_aacp?_\d+k?$/i) && !rawTitle.match(/^\w+_mp3_\d+k?$/i)) {
                      metadata.song = rawTitle;
                      
                      // Try to split into artist and title (various separators)
                      let parts = rawTitle.split(' - ');
                      if (parts.length === 1) {
                        parts = rawTitle.split(' – '); // em dash
                      }
                      if (parts.length === 1) {
                        parts = rawTitle.split(' | ');
                      }
                      
                      if (parts.length >= 2) {
                        metadata.artist = parts[0].trim();
                        metadata.title = parts.slice(1).join(' - ').trim();
                      } else if (parts.length === 1 && rawTitle.length > 0) {
                        // If no separator, use the whole thing as title
                        metadata.title = rawTitle.trim();
                      }
                    }
                  }
                }
                
                metadataFound = true;
                response.data.destroy();
              }
            });

            // Wait a bit for metadata
            await new Promise(resolve => setTimeout(resolve, 2000));
          }

          // Close the stream
          if (response.data && !response.data.destroyed) {
            response.data.destroy();
          }

          // If no metadata found from ICY, try external APIs
          if (!metadata.title && !metadata.artist && !metadata.song) {
            logger.info(`[Metadata] No ICY metadata found, trying external sources for ${channel.name}`);
            
            try {
              const externalMetadata = await getRadioStationMetadata(channel.name, channel.url);
              if (externalMetadata) {
                metadata.title = externalMetadata.title;
                metadata.artist = externalMetadata.artist;
                if (externalMetadata.title && externalMetadata.artist) {
                  metadata.song = `${externalMetadata.artist} - ${externalMetadata.title}`;
                } else if (externalMetadata.title) {
                  metadata.song = externalMetadata.title;
                }
                logger.info(`[Metadata] External metadata found: ${metadata.song}`);
              }
            } catch (externalError) {
              logger.error(`[Metadata] External metadata fetch failed: ${externalError.message}`);
            }
          }

          res.json(metadata);

        } catch (streamError) {
          logger.error('Error fetching stream metadata:', streamError.message);
          
          // Try external metadata as fallback
          try {
            const externalMetadata = await getRadioStationMetadata(channel.name, channel.url);
            if (externalMetadata) {
              return res.json({
                channelId: parseInt(channelId),
                channelName: channel.name,
                title: externalMetadata.title,
                artist: externalMetadata.artist,
                song: externalMetadata.artist && externalMetadata.title 
                  ? `${externalMetadata.artist} - ${externalMetadata.title}`
                  : externalMetadata.title,
                streamTitle: channel.name,
                bitrate: null,
                genre: null,
                url: null,
                source: externalMetadata.source
              });
            }
          } catch (externalError) {
            logger.error(`[Metadata] External metadata fallback failed: ${externalError.message}`);
          }
          
          // Return basic info if everything fails
          res.json({
            channelId: parseInt(channelId),
            channelName: channel.name,
            title: null,
            artist: null,
            song: null,
            streamTitle: channel.name,
            bitrate: null,
            genre: null,
            url: null,
            error: 'Unable to fetch stream metadata'
          });
        }
      }
    );
  } catch (error) {
    logger.error('Metadata fetch error:', error);
    res.status(500).json({ error: 'Failed to fetch metadata' });
  }
});

module.exports = router;
