from abc import ABC, abstractmethod
from typing import List, Optional
from datetime import datetime, timedelta, timezone
from ...project.storage import get_storage_instance


class TelegramMessage:
    """Data model for Telegram messages."""
    
    def __init__(self, time: datetime, text: str, message_id: Optional[int] = None):
        self.time = time
        self.text = text
        self.message_id = message_id
    
    def to_dict(self) -> dict:
        """Convert to dictionary for storage."""
        return {
            'time': self.time.isoformat(),
            'text': self.text,
            'message_id': self.message_id
        }
    
    @classmethod
    def from_dict(cls, data: dict) -> 'TelegramMessage':
        """Create from dictionary."""
        return cls(
            time=datetime.fromisoformat(data['time']),
            text=data['text'],
            message_id=data.get('message_id')
        )


class TelegramDataProvider(ABC):
    """Abstract base class for Telegram data retrieval and storage."""
    
    def __init__(self, channel_username: str, proxy_port: Optional[int] = None):
        self.channel_username = channel_username
        self.proxy_port = proxy_port
        self.storage = get_storage_instance()
    
    def get_export_path(self, filename: str) -> str:
        """Get the export path for Telegram data."""
        return self.storage.get_path('telegram', filename, storage_type='user')
    
    def fetch_data(self, max_pages: int = 10, max_messages: int = 150, days: int = 1) -> List[TelegramMessage]:
        """Fetch Telegram channel messages."""
        import requests
        from bs4 import BeautifulSoup
        import time
        import random
        
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
                          '(KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36'
        }
        proxies = None
        if self.proxy_port is not None:
            proxies = {
                'http': f'http://localhost:{self.proxy_port}',
                'https': f'http://localhost:{self.proxy_port}'
            }
        
        messages = []
        now_utc = datetime.now(timezone.utc)
        time_limit = now_utc - timedelta(days=days)
        
        url_base = f"https://t.me/s/{self.channel_username}"
        page = 1
        before_id = None
        
        while page <= max_pages and len(messages) < max_messages:
            current_url = f"{url_base}?before={before_id}" if before_id else url_base
            
            try:
                resp = requests.get(current_url, headers=headers, proxies=proxies, timeout=15)
                if resp.status_code != 200:
                    break
                
                soup = BeautifulSoup(resp.text, 'html.parser')
                
                page_messages = []
                min_post_id = None
                
                for widget in soup.find_all('div', class_='tgme_widget_message'):
                    data_post = widget.get('data-post')
                    message_id = None
                    if data_post and '/' in data_post:
                        try:
                            message_id = int(data_post.split('/')[-1])
                            if min_post_id is None or message_id < min_post_id:
                                min_post_id = message_id
                        except ValueError:
                            pass
                    
                    time_tag = widget.find('time', class_='time')
                    if not time_tag or not time_tag.get('datetime'):
                        continue
                    time_str = time_tag['datetime']
                    msg_time = datetime.fromisoformat(time_str.replace('Z', '+00:00'))
                    
                    if msg_time < time_limit:
                        min_post_id = None
                        break
                    
                    text_div = widget.find('div', class_='tgme_widget_message_text')
                    text = text_div.get_text(strip=True) if text_div else ''
                    
                    if text:
                        page_messages.append(TelegramMessage(
                            time=msg_time,
                            text=text,
                            message_id=message_id
                        ))
                
                messages.extend(page_messages)
                
                if min_post_id is None or len(page_messages) == 0:
                    break
                    
                before_id = min_post_id
                page += 1
                
                time.sleep(random.uniform(1.2, 2.8))
                
            except Exception:
                break
        
        return messages
    
    @abstractmethod
    def store_data(self, messages: List[TelegramMessage]) -> bool:
        """Store Telegram messages."""
        pass
    
    @abstractmethod
    def process_data(self, messages: List[TelegramMessage]) -> List[TelegramMessage]:
        """Process Telegram messages."""
        pass
