import os
import feedparser
from typing import Any, Dict, List, Optional
from datetime import datetime
from src.base_scraper import BaseScraper, ScraperConfig


class BaseRSSScraper(BaseScraper):
    """Base class for RSS feed scrapers."""
    
    def __init__(self, config: ScraperConfig, feed_url_env: str):
        super().__init__(config)
        self.feed_url = os.getenv(feed_url_env, '')
        if not self.feed_url:
            self.logger.error(f"No feed URL found in environment variable {feed_url_env}")

    def fetch_feed(self) -> List[Dict[str, Any]]:
        """Fetch and parse RSS feed."""
        try:
            self.logger.info(f"Fetching RSS feed from {self.feed_url}")
            feed = feedparser.parse(self.feed_url)
            
            # Check if it's a feedparser result or a dict (for testing)
            if hasattr(feed, 'bozo'):
                if feed.bozo:
                    self.logger.warning(f"Feed parsing had issues: {feed.bozo_exception}")
                entries = feed.get('entries', [])
            else:
                # Handle dict input (for testing)
                entries = feed.get('entries', []) if isinstance(feed, dict) else []
            
            self.logger.info(f"Found {len(entries)} entries in feed")
            
            # Convert entries to list of dicts for easier handling
            processed_entries = []
            for entry in entries:
                processed_entry = dict(entry)
                processed_entries.append(processed_entry)
            
            return processed_entries
            
        except Exception as e:
            self.logger.error(f"Error fetching RSS feed: {e}")
            return []

    def fetch_content(self, max_items: int = None) -> List[Dict[str, Any]]:
        """Fetch content from RSS feed.
        
        Args:
            max_items: Maximum number of items to return (None for all items)
        """
        items = self.fetch_feed()
        if max_items and max_items > 0:
            return items[:max_items]
        return items

    def get_incremental_items(self, items: List[Dict[str, Any]], state: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Get only new items since last sync."""
        if not state:
            return items
        
        last_item_id = state.get('last_item_id')
        if not last_item_id:
            return items
        
        # Find the index of the last synced item
        last_index = -1
        for i, item in enumerate(items):
            if item.get('id') == last_item_id or item.get('guid') == last_item_id:
                last_index = i
                break
        
        if last_index == -1:
            # Last item not found, return all items
            self.logger.warning(f"Last synced item {last_item_id} not found in feed")
            return items
        
        # Return only items before the last synced one (newer items)
        return items[:last_index]

    def update_state(self, state: Dict[str, Any], items: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Update state with latest item information."""
        if not items:
            return state
        
        # Get the first item (most recent)
        latest_item = items[0]
        
        state['last_item_id'] = latest_item.get('id') or latest_item.get('guid')
        state['last_item_date'] = latest_item.get('published')
        state['last_sync'] = datetime.now(self.tz).isoformat()
        state['item_count'] = len(items)
        
        return state


class RSSScraperMailChimp(BaseRSSScraper):
    """MailChimp RSS feed scraper."""
    
    def __init__(self, config: ScraperConfig):
        super().__init__(config, 'MAILCHIMP_RSS_URL')

    def format_markdown(self, items: List[Dict[str, Any]]) -> str:
        """Format RSS items as markdown."""
        markdown_sections = []
        
        for item in items:
            section = []
            
            # ID
            item_id = item.get('id') or item.get('guid', 'N/A')
            section.append(f"# ID: {item_id}")
            section.append("")
            
            # Title
            title = item.get('title', 'Untitled')
            section.append(f"## Title: {title}")
            section.append("")
            
            # Type
            section.append("## Type: newsletter")
            section.append("")
            
            # Link
            link = item.get('link', '')
            section.append(f"## Link: {link}")
            section.append("")
            
            # Publish Date
            pub_date = item.get('published') or item.get('pubDate', '')
            section.append(f"## Publish Date: {pub_date}")
            section.append("")
            
            # Content/Description
            section.append("## Content:")
            
            # Try to get full content first, then summary, then description
            content = item.get('content')
            if content and isinstance(content, list) and len(content) > 0:
                content_html = content[0].get('value', '')
                if content_html:
                    content_md = self.convert_to_markdown(content_html)
                    section.append(content_md)
            elif item.get('summary'):
                summary_md = self.convert_to_markdown(item.get('summary'))
                section.append(summary_md)
            elif item.get('description'):
                desc_md = self.convert_to_markdown(item.get('description'))
                section.append(desc_md)
            
            section.append("")
            
            # Separator
            section.append("-" * 50)
            section.append("")
            
            markdown_sections.append('\n'.join(section))
        
        return '\n'.join(markdown_sections)


class RSSScraperPodcast(BaseRSSScraper):
    """Podcast RSS feed scraper."""
    
    def __init__(self, config: ScraperConfig):
        super().__init__(config, 'PODCAST_RSS_URL')

    def extract_audio_link(self, item: Dict[str, Any]) -> Optional[str]:
        """Extract audio link from podcast item."""
        # Check for enclosures (standard podcast format)
        enclosures = item.get('enclosures', [])
        for enclosure in enclosures:
            if 'href' in enclosure:
                return enclosure['href']
            elif 'url' in enclosure:
                return enclosure['url']
        
        # Check for media content
        media_content = item.get('media_content', [])
        for media in media_content:
            if media.get('type', '').startswith('audio'):
                return media.get('url')
        
        return None

    def extract_image_link(self, item: Dict[str, Any]) -> Optional[str]:
        """Extract image link from podcast item."""
        # Check for iTunes image
        if 'image' in item:
            if isinstance(item['image'], dict):
                return item['image'].get('href') or item['image'].get('url')
            elif isinstance(item['image'], str):
                return item['image']
        
        # Check for media thumbnail
        media_thumbnail = item.get('media_thumbnail', [])
        if media_thumbnail and len(media_thumbnail) > 0:
            return media_thumbnail[0].get('url')
        
        return None

    def fetch_content(self, max_items: int = None) -> List[Dict[str, Any]]:
        """Fetch and enrich podcast content.
        
        Args:
            max_items: Maximum number of items to return (None for all items)
        """
        items = super().fetch_content(max_items=max_items)
        
        # Enrich with audio and image links
        for item in items:
            item['audio_link'] = self.extract_audio_link(item)
            item['image_link'] = self.extract_image_link(item)
            item['duration'] = item.get('itunes_duration', '')
            
            # Download audio file if configured
            if item['audio_link'] and self.config.data_dir:
                # Extract filename from URL
                audio_filename = item['audio_link'].split('/')[-1]
                # Store reference for later download
                item['audio_filename'] = audio_filename
        
        return items

    def format_markdown(self, items: List[Dict[str, Any]]) -> str:
        """Format podcast items as markdown."""
        markdown_sections = []
        
        for item in items:
            section = []
            
            # ID
            item_id = item.get('id') or item.get('guid', 'N/A')
            section.append(f"# ID: {item_id}")
            section.append("")
            
            # Title
            title = item.get('title', 'Untitled')
            section.append(f"## Title: {title}")
            section.append("")
            
            # Subtitle
            subtitle = item.get('subtitle', '')
            if subtitle:
                section.append(f"## Subtitle: {subtitle}")
                section.append("")
            
            # Type
            section.append("## Type: podcast")
            section.append("")
            
            # Author
            author = item.get('author') or item.get('itunes_author', 'Unknown')
            section.append(f"## Author: {author}")
            section.append("")
            
            # Publish Date
            pub_date = item.get('published') or item.get('pubDate', '')
            section.append(f"## Publish Date: {pub_date}")
            section.append("")
            
            # Duration
            duration = item.get('duration') or item.get('itunes_duration', '')
            if duration:
                section.append(f"## Duration: {duration}")
                section.append("")
            
            # Audio Link
            audio_link = item.get('audio_link', '')
            if audio_link:
                section.append(f"## Audio Link: {audio_link}")
                section.append("")
            
            # Image
            image_link = item.get('image_link', '')
            if image_link:
                section.append(f"## Image: {image_link}")
                section.append("")
            
            # Episode Link
            link = item.get('link', '')
            section.append(f"## Episode Link: {link}")
            section.append("")
            
            # Description
            section.append("## Description:")
            
            # Try to get description
            if item.get('description'):
                desc_md = self.convert_to_markdown(item.get('description'))
                section.append(desc_md)
            elif item.get('summary'):
                summary_md = self.convert_to_markdown(item.get('summary'))
                section.append(summary_md)
            
            section.append("")
            
            # Separator
            section.append("-" * 50)
            section.append("")
            
            markdown_sections.append('\n'.join(section))
        
        return '\n'.join(markdown_sections)