import os
import time
import random
from typing import Any, Dict, List, Optional
from datetime import datetime, timedelta
from pathlib import Path
import json
import re
from scrapling import StealthyFetcher, Adaptor
from src.base_scraper import BaseScraper, ScraperConfig


class TikTokScraperScrapling(BaseScraper):
    """TikTok scraper using Scrapling with Camofaux for browser automation."""
    
    def __init__(self, config: ScraperConfig):
        super().__init__(config)
        self.target_username = os.getenv('TIKTOK_TARGET', 'hvacknowitall')
        self.base_url = f"https://www.tiktok.com/@{self.target_username}"
        
    def _human_delay(self, min_seconds: float = 2, max_seconds: float = 5) -> None:
        """Add human-like delays between actions."""
        delay = random.uniform(min_seconds, max_seconds)
        self.logger.debug(f"Waiting {delay:.2f} seconds (human-like delay)...")
        time.sleep(delay)
        
    def fetch_posts(self, max_posts: int = 20) -> List[Dict[str, Any]]:
        """Fetch posts from TikTok profile using Scrapling."""
        posts_data = []
        
        try:
            self.logger.info(f"Fetching TikTok posts from @{self.target_username}")
            
            # Use StealthyFetcher with Camofaux for anti-bot detection
            fetcher = StealthyFetcher(
                browser_type="firefox",
                headless=True,
                network_idle=True
            )
            
            # Fetch the profile page
            self.logger.info(f"Loading {self.base_url}")
            response = fetcher.fetch(self.base_url)
            
            if not response:
                self.logger.error("Failed to load TikTok profile")
                return posts_data
            
            # Wait for human-like delay
            self._human_delay(2, 4)
            
            # Extract video items
            video_items = response.css("[data-e2e='user-post-item']")
            
            if not video_items:
                self.logger.warning("No video items found with primary selector, trying alternatives")
                # Try alternative selectors
                video_items = response.css("div[class*='DivItemContainer']")
                
                if not video_items:
                    video_items = response.css("div[class*='video-feed-item']")
                
                if not video_items:
                    # Look for any links to videos
                    video_links = response.css("a[href*='/video/']")
                    if video_links:
                        self.logger.info(f"Found {len(video_links)} video links directly")
                        for idx, link in enumerate(video_links[:max_posts]):
                            try:
                                href = link.attrs.get('href', '')
                                if not href:
                                    continue
                                
                                if not href.startswith('http'):
                                    href = f"https://www.tiktok.com{href}"
                                
                                video_id_match = re.search(r'/video/(\d+)', href)
                                video_id = video_id_match.group(1) if video_id_match else f"video_{idx}"
                                
                                post_data = {
                                    'id': video_id,
                                    'type': 'video',
                                    'caption': '',
                                    'author': self.target_username,
                                    'publish_date': datetime.now(self.tz).isoformat(),
                                    'link': href,
                                    'views': 0,
                                    'platform': 'tiktok'
                                }
                                
                                posts_data.append(post_data)
                                
                            except Exception as e:
                                self.logger.error(f"Error processing video link {idx}: {e}")
                                continue
            
            self.logger.info(f"Found {len(video_items)} video items on page")
            
            # Process video items if found
            for idx, item in enumerate(video_items[:max_posts]):
                try:
                    # Extract video link
                    link_element = item.css("a[href*='/video/']")
                    if not link_element:
                        link_element = item.css("a")
                        if link_element:
                            # Try different ways to get href
                            if hasattr(link_element[0], 'attrs'):
                                href = link_element[0].attrs.get('href', '')
                            else:
                                href = link_element[0].get('href', '')
                            if '/video/' not in href:
                                continue
                    
                    if not link_element:
                        continue
                    
                    # Get the href attribute properly
                    if hasattr(link_element[0], 'attrs'):
                        video_url = link_element[0].attrs.get('href', '')
                    elif hasattr(link_element[0], 'get'):
                        video_url = link_element[0].get('href', '')
                    else:
                        # Try extracting href from the string representation
                        video_url = item.css("a[href*='/video/']::attr(href)")
                        video_url = video_url[0] if video_url else ''
                    if not video_url.startswith('http'):
                        video_url = f"https://www.tiktok.com{video_url}"
                    
                    # Extract video ID from URL
                    video_id_match = re.search(r'/video/(\d+)', video_url)
                    video_id = video_id_match.group(1) if video_id_match else f"video_{idx}"
                    
                    # Extract caption/description
                    caption = ""
                    caption_element = item.css("div[data-e2e='browse-video-desc'] span::text")
                    if caption_element:
                        caption = caption_element[0] if isinstance(caption_element, list) else str(caption_element)
                    
                    if not caption:
                        caption_element = item.css("div[class*='DivContainer'] span::text")
                        if caption_element:
                            caption = caption_element[0] if isinstance(caption_element, list) else str(caption_element)
                    
                    # Extract view count
                    views_text = "0"
                    views_element = item.css("strong[data-e2e='video-views']::text")
                    if views_element:
                        views_text = views_element[0] if isinstance(views_element, list) else str(views_element)
                    
                    if not views_text or views_text == "0":
                        views_element = item.css("strong::text")
                        if views_element:
                            views_text = views_element[0] if isinstance(views_element, list) else str(views_element)
                    
                    views = self._parse_count(views_text)
                    
                    post_data = {
                        'id': video_id,
                        'type': 'video',
                        'caption': caption,
                        'author': self.target_username,
                        'publish_date': datetime.now(self.tz).isoformat(),
                        'link': video_url,
                        'views': views,
                        'platform': 'tiktok'
                    }
                    
                    posts_data.append(post_data)
                    
                    if idx % 5 == 0 and idx > 0:
                        self.logger.info(f"Processed {idx} videos...")
                    
                except Exception as e:
                    self.logger.error(f"Error processing video item {idx}: {e}")
                    continue
            
            # If no posts found, try extracting from page scripts
            if not posts_data:
                self.logger.info("No posts found via selectors, checking page scripts...")
                scripts = response.css("script")
                
                for script in scripts:
                    script_text = script.text
                    if '__UNIVERSAL_DATA_FOR_REHYDRATION__' in script_text or 'window.__INIT_PROPS__' in script_text:
                        try:
                            # Extract JSON data
                            json_match = re.search(r'\{.*\}', script_text)
                            if json_match:
                                data = json.loads(json_match.group())
                                self.logger.info("Found data in script tag, parsing...")
                                # The structure varies, but look for video URLs
                                # This is a simplified approach
                                urls = re.findall(r'"/video/(\d+)"', str(data))
                                for video_id in urls[:max_posts]:
                                    post_data = {
                                        'id': video_id,
                                        'type': 'video',
                                        'caption': '',
                                        'author': self.target_username,
                                        'publish_date': datetime.now(self.tz).isoformat(),
                                        'link': f"https://www.tiktok.com/@{self.target_username}/video/{video_id}",
                                        'views': 0,
                                        'platform': 'tiktok'
                                    }
                                    if post_data not in posts_data:
                                        posts_data.append(post_data)
                        except Exception as e:
                            self.logger.debug(f"Could not parse script data: {e}")
                            continue
            
            self.logger.info(f"Successfully fetched {len(posts_data)} TikTok posts")
            
        except Exception as e:
            self.logger.error(f"Error fetching TikTok posts: {e}")
            import traceback
            self.logger.error(traceback.format_exc())
        
        return posts_data
    
    def _parse_count(self, count_str: str) -> int:
        """Parse TikTok view/like counts (e.g., '1.2M' -> 1200000)."""
        if not count_str:
            return 0
            
        count_str = str(count_str).strip().upper()
        
        try:
            if 'K' in count_str:
                num = re.search(r'([\d.]+)', count_str)
                if num:
                    return int(float(num.group(1)) * 1000)
            elif 'M' in count_str:
                num = re.search(r'([\d.]+)', count_str)
                if num:
                    return int(float(num.group(1)) * 1000000)
            elif 'B' in count_str:
                num = re.search(r'([\d.]+)', count_str)
                if num:
                    return int(float(num.group(1)) * 1000000000)
            else:
                # Remove any non-numeric characters
                return int(re.sub(r'[^\d]', '', count_str) or 0)
        except:
            return 0
    
    def fetch_content(self) -> List[Dict[str, Any]]:
        """Fetch all content from TikTok."""
        return self.fetch_posts(max_posts=20)
    
    def format_markdown(self, items: List[Dict[str, Any]]) -> str:
        """Format TikTok content as markdown."""
        markdown_sections = []
        
        for item in items:
            section = []
            
            # ID
            section.append(f"# ID: {item.get('id', 'N/A')}")
            section.append("")
            
            # Type
            section.append(f"## Type: {item.get('type', 'video')}")
            section.append("")
            
            # Author
            section.append(f"## Author: @{item.get('author', 'Unknown')}")
            section.append("")
            
            # Publish Date
            section.append(f"## Publish Date: {item.get('publish_date', '')}")
            section.append("")
            
            # Link
            section.append(f"## Link: {item.get('link', '')}")
            section.append("")
            
            # Views
            views = item.get('views', 0)
            section.append(f"## Views: {views:,}")
            section.append("")
            
            # Caption
            section.append("## Caption:")
            caption = item.get('caption', '')
            if caption:
                section.append(caption)
            section.append("")
            
            # Separator
            section.append("-" * 50)
            section.append("")
            
            markdown_sections.append('\n'.join(section))
        
        return '\n'.join(markdown_sections)
    
    def get_incremental_items(self, items: List[Dict[str, Any]], state: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Get only new videos since last sync."""
        if not state:
            return items
        
        last_video_id = state.get('last_video_id')
        
        if not last_video_id:
            return items
        
        # Filter for videos newer than the last synced
        new_items = []
        for item in items:
            if item.get('id') == last_video_id:
                break  # Found the last synced video
            new_items.append(item)
        
        return new_items
    
    def update_state(self, state: Dict[str, Any], items: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Update state with latest video information."""
        if not items:
            return state
        
        # Get the first item (most recent)
        latest_item = items[0]
        
        state['last_video_id'] = latest_item.get('id')
        state['last_video_date'] = latest_item.get('publish_date')
        state['last_sync'] = datetime.now(self.tz).isoformat()
        state['video_count'] = len(items)
        
        return state