"""MoreStore API Client"""

import requests
import threading
import uuid
import json
import time
from typing import Optional
from pathlib import Path


class MoreStoreClient:
    """Client for interacting with MoreStore.ai API"""
    
    def __init__(self, base_url: str = "https://morestore.ai"):
        """
        Initialize the MoreStore client
        
        Args:
            base_url: Base URL of the MoreStore API (default: https://morestore.ai)
        """
        self.base_url = base_url.rstrip('/')
        self.api_url = f"{self.base_url}/api"
    
    def generate_perfect_scene(
        self,
        image_path: str,
        output_path: Optional[str] = None,
        brand_name: Optional[str] = None,
        product_name: Optional[str] = None,
        custom_prompt: Optional[str] = None,
        scale_to_megapixels: float = 1.0,
        show_progress: bool = True
    ) -> str:
        """
        Generate a perfect scene for a product image
        
        Args:
            image_path: Path to the input image file
            output_path: Path to save the generated image (default: input name with '_perfect_scene' suffix)
            brand_name: Optional brand name for context
            product_name: Optional product name
            custom_prompt: Optional custom prompt (auto-generated if not provided)
            scale_to_megapixels: Target megapixels for image scaling (default: 1.0)
            show_progress: Whether to show progress updates (default: True)
        
        Returns:
            Path to the generated image file
        
        Raises:
            FileNotFoundError: If the input image file doesn't exist
            requests.RequestException: If the API request fails
        """
        image_path = Path(image_path)
        if not image_path.exists():
            raise FileNotFoundError(f"Image file not found: {image_path}")
        
        # Generate output path if not provided
        if output_path is None:
            output_path = image_path.parent / f"{image_path.stem}_perfect_scene.jpg"
        else:
            output_path = Path(output_path)
        
        # Generate session ID for progress tracking
        session_id = str(uuid.uuid4())
        generation_complete = threading.Event()
        download_url = [None]  # Use list to allow modification in thread
        
        if show_progress:
            progress_thread = self._start_progress_listener(session_id, generation_complete, download_url)
            time.sleep(1)  # Give progress listener time to connect
        
        # Prepare file upload
        with open(image_path, 'rb') as image_file:
            # Determine content type from file extension
            content_type = 'image/jpeg'
            if image_path.suffix.lower() == '.png':
                content_type = 'image/png'
            
            files = {'file': (image_path.name, image_file, content_type)}
            
            data = {
                'session_id': session_id,
                'scale_to_megapixels': str(scale_to_megapixels),
            }
            
            if brand_name:
                data['brand_name'] = brand_name
            if product_name:
                data['product_name'] = product_name
            if custom_prompt:
                data['custom_prompt'] = custom_prompt
            
            try:
                if show_progress:
                    print(f"\n📤 Uploading image and starting generation...")
                
                response = requests.post(
                    f"{self.api_url}/perfect-scene",
                    files=files,
                    data=data,
                    timeout=30  # Short timeout for initial request
                )
                
                # Handle 202 Accepted (async processing)
                if response.status_code == 202:
                    response_data = response.json()
                    if response_data.get('session_id'):
                        session_id = response_data['session_id']
                    
                    if show_progress:
                        print(f"✅ Generation started (session: {session_id[:8]}...)")
                    
                    # Wait for generation to complete via progress stream
                    if show_progress and not generation_complete.wait(timeout=300):
                        raise requests.RequestException("Timeout waiting for generation to complete")
                    
                    # Download the image from the URL provided in completion event
                    if download_url[0]:
                        if show_progress:
                            print(f"📥 Downloading generated image...")
                        
                        download_response = requests.get(
                            f"{self.base_url}{download_url[0]}",
                            timeout=60
                        )
                        
                        if download_response.status_code == 200:
                            with open(output_path, 'wb') as f:
                                f.write(download_response.content)
                            
                            if show_progress:
                                print(f"\n✅ Perfect scene image saved successfully!")
                            
                            return str(output_path)
                        else:
                            raise requests.RequestException(f"Failed to download image: {download_response.status_code}")
                    else:
                        raise requests.RequestException("No download URL received from completion event")
                
                # Handle 200 OK (direct image response - legacy/fallback)
                elif response.status_code == 200:
                    # Save the generated image
                    with open(output_path, 'wb') as f:
                        f.write(response.content)
                    
                    if show_progress:
                        print(f"\n✅ Perfect scene image saved successfully!")
                        if 'X-Generation-Time' in response.headers:
                            print(f"⏱️  Total generation time: {response.headers['X-Generation-Time']} seconds")
                    
                    return str(output_path)
                else:
                    error_msg = f"Error: {response.status_code}"
                    if response.text:
                        error_msg += f"\nResponse: {response.text}"
                    raise requests.RequestException(error_msg)
            
            except requests.exceptions.RequestException as e:
                if show_progress:
                    print(f"\n❌ Request error: {e}")
                generation_complete.set()
                raise
        
        return str(output_path)
    
    def analyze_brand(self, website_url: str, clear_cache: bool = False) -> dict:
        """
        Analyze a brand's website
        
        Args:
            website_url: The URL of the website to analyze
            clear_cache: Force fresh analysis (default: False)
        
        Returns:
            Dictionary containing analysis results
        """
        response = requests.post(
            f"{self.api_url}/analyze-brand",
            json={"website_url": website_url, "clear_cache": clear_cache}
        )
        response.raise_for_status()
        return response.json()
    
    def get_analysis(self, domain: str) -> dict:
        """
        Retrieve cached analysis results for a domain
        
        Args:
            domain: The domain name (e.g., "example.com")
        
        Returns:
            Dictionary containing cached analysis data
        """
        response = requests.get(f"{self.api_url}/analysis-cache/{domain}")
        response.raise_for_status()
        return response.json()
    
    def clear_cache(self, domain: str) -> dict:
        """
        Clear cached analysis for a domain
        
        Args:
            domain: The domain name (e.g., "example.com")
        
        Returns:
            Dictionary containing success message
        """
        response = requests.delete(f"{self.api_url}/analysis-cache/{domain}")
        response.raise_for_status()
        return response.json()
    
    def analyze_product(
        self,
        image_path: str,
        brand_name: Optional[str] = None,
        product_name: Optional[str] = None
    ) -> dict:
        """
        Analyze a product image
        
        Args:
            image_path: Path to the product image file
            brand_name: Optional brand name for context
            product_name: Optional product name
        
        Returns:
            Dictionary containing product analysis results
        """
        image_path = Path(image_path)
        if not image_path.exists():
            raise FileNotFoundError(f"Image file not found: {image_path}")
        
        with open(image_path, 'rb') as image_file:
            files = {'file': (image_path.name, image_file, 'image/jpeg')}
            data = {}
            if brand_name:
                data['brand_name'] = brand_name
            if product_name:
                data['product_name'] = product_name
            
            response = requests.post(
                f"{self.api_url}/analyze-product",
                files=files,
                data=data
            )
            response.raise_for_status()
            return response.json()
    
    def batch_analyze_products(self, products: list, show_progress: bool = True) -> dict:
        """
        Analyze multiple products with streaming progress
        
        Args:
            products: List of product dictionaries with 'product_name', 'product_description', 'price'
            show_progress: Whether to show progress updates (default: True)
        
        Returns:
            Dictionary containing all analysis results
        """
        response = requests.post(
            f"{self.api_url}/batch-analyze-products",
            json={"products": products},
            stream=True
        )
        response.raise_for_status()
        
        results = []
        for line in response.iter_lines():
            if line:
                line_str = line.decode('utf-8')
                if line_str.startswith('data: '):
                    data = json.loads(line_str[6:])
                    if show_progress:
                        if data.get('type') == 'progress':
                            print(f"📊 {data.get('message', 'Processing...')}")
                        elif data.get('type') == 'result':
                            print(f"✅ {data.get('product_name', 'Product')} analyzed")
                        elif data.get('type') == 'complete':
                            print(f"🎉 All products analyzed!")
                    if data.get('type') == 'complete':
                        return data
        
        return {"results": results}
    
    def generate_perfect_prompt(
        self,
        image_path: str,
        brand_name: Optional[str] = None,
        product_name: Optional[str] = None,
        color: Optional[str] = None,
        theme: Optional[str] = None,
        suggestion: Optional[str] = None
    ) -> dict:
        """
        Generate perfect prompt for a product image
        
        Args:
            image_path: Path to the product image file
            brand_name: Optional brand name
            product_name: Optional product name
            color: Optional color preference
            theme: Optional theme preference
            suggestion: Optional user suggestion
        
        Returns:
            Dictionary containing generated prompt and metadata
        """
        image_path = Path(image_path)
        if not image_path.exists():
            raise FileNotFoundError(f"Image file not found: {image_path}")
        
        with open(image_path, 'rb') as image_file:
            files = {'file': (image_path.name, image_file, 'image/jpeg')}
            data = {}
            if brand_name:
                data['brand_name'] = brand_name
            if product_name:
                data['product_name'] = product_name
            if color:
                data['color'] = color
            if theme:
                data['theme'] = theme
            if suggestion:
                data['suggestion'] = suggestion
            
            response = requests.post(
                f"{self.api_url}/perfect-prompt",
                files=files,
                data=data
            )
            response.raise_for_status()
            return response.json()
    
    def generate_perfect_ad(
        self,
        image_path: str,
        output_path: Optional[str] = None,
        brand_name: Optional[str] = None,
        product_name: Optional[str] = None
    ) -> str:
        """
        Generate perfect ad with text overlay
        
        Args:
            image_path: Path to the product image file
            output_path: Path to save the generated ad (default: input name with "_ad" suffix)
            brand_name: Optional brand name
            product_name: Optional product name
        
        Returns:
            Path to the generated ad image file
        """
        image_path = Path(image_path)
        if not image_path.exists():
            raise FileNotFoundError(f"Image file not found: {image_path}")
        
        if output_path is None:
            output_path = image_path.parent / f"{image_path.stem}_ad.jpg"
        else:
            output_path = Path(output_path)
        
        with open(image_path, 'rb') as image_file:
            files = {'file': (image_path.name, image_file, 'image/jpeg')}
            data = {}
            if brand_name:
                data['brand_name'] = brand_name
            if product_name:
                data['product_name'] = product_name
            
            response = requests.post(
                f"{self.api_url}/perfect-ad",
                files=files,
                data=data
            )
            response.raise_for_status()
            
            with open(output_path, 'wb') as f:
                f.write(response.content)
            
            return str(output_path)
    
    def batch_generate_perfect_scenes(
        self,
        image_paths: list,
        scene_prompts: Optional[list] = None,
        show_progress: bool = True
    ) -> dict:
        """
        Generate perfect scenes for multiple products
        
        Args:
            image_paths: List of paths to product image files
            scene_prompts: Optional list of scene prompts (one per image)
            show_progress: Whether to show progress updates (default: True)
        
        Returns:
            Dictionary containing results
        """
        files_data = []
        for img_path in image_paths:
            img_path = Path(img_path)
            if not img_path.exists():
                raise FileNotFoundError(f"Image file not found: {img_path}")
            with open(img_path, 'rb') as f:
                files_data.append(('files', (img_path.name, f.read(), 'image/jpeg')))
        
        data = {}
        if scene_prompts:
            data['scene_prompts'] = json.dumps(scene_prompts)
        
        response = requests.post(
            f"{self.api_url}/batch-generate-perfect-scenes",
            files=files_data,
            data=data,
            stream=True
        )
        response.raise_for_status()
        
        for line in response.iter_lines():
            if line:
                line_str = line.decode('utf-8')
                if line_str.startswith('data: '):
                    event_data = json.loads(line_str[6:])
                    if show_progress:
                        if event_data.get('type') == 'progress':
                            print(f"📊 {event_data.get('message', 'Processing...')}")
                        elif event_data.get('type') == 'result':
                            print(f"✅ {event_data.get('filename', 'Scene')} generated")
                        elif event_data.get('type') == 'complete':
                            print(f"🎉 All scenes generated!")
                            return event_data
        
        return {}
    
    def generate_batch_seasonal(
        self,
        products: list,
        season: str
    ) -> dict:
        """
        Generate seasonal hero images
        
        Args:
            products: List of product dictionaries with 'name' and 'image_url'
            season: Season name (halloween, christmas, spring, summer, autumn, winter)
        
        Returns:
            Dictionary containing generated images
        """
        response = requests.post(
            f"{self.api_url}/generate-batch-seasonal",
            json={"products": products, "season": season}
        )
        response.raise_for_status()
        return response.json()
    
    def closest_brands(
        self,
        domain: str,
        top_k: int = 5,
        keep_model_loaded: bool = False
    ) -> dict:
        """
        Find brands with similar identity
        
        Args:
            domain: The domain to find similar brands for
            top_k: Number of similar brands to return (default: 5)
            keep_model_loaded: Keep model in memory (default: False)
        
        Returns:
            Dictionary containing closest brands
        """
        response = requests.get(
            f"{self.api_url}/brand-clustering/closest-brands/{domain}",
            params={"top_k": top_k, "keep_model_loaded": keep_model_loaded}
        )
        response.raise_for_status()
        return response.json()
    
    def farthest_brands(
        self,
        domain: str,
        top_k: int = 5
    ) -> dict:
        """
        Find brands with contrasting identity
        
        Args:
            domain: The domain to find contrasting brands for
            top_k: Number of contrasting brands to return (default: 5)
        
        Returns:
            Dictionary containing farthest brands
        """
        response = requests.get(
            f"{self.api_url}/brand-clustering/farthest-brands/{domain}",
            params={"top_k": top_k}
        )
        response.raise_for_status()
        return response.json()
    
    def _start_progress_listener(self, session_id: str, generation_complete: threading.Event, download_url: list) -> threading.Thread:
        """Start a background thread to listen to progress events"""
        
        def listen_to_progress():
            url = f'{self.api_url}/progress/{session_id}'
            
            try:
                response = requests.get(url, stream=True, timeout=300)
                
                print("📡 Connected to progress stream...")
                
                for line in response.iter_lines():
                    if line:
                        line_str = line.decode('utf-8')
                        
                        # Skip SSE keepalive comments
                        if line_str.startswith(':'):
                            continue
                        
                        # Parse SSE data lines
                        if line_str.startswith('data: '):
                            try:
                                data_str = line_str[6:]  # Remove 'data: ' prefix
                                event_data = json.loads(data_str)
                                
                                event_type = event_data.get('type', 'unknown')
                                message_data = event_data.get('data', {})
                                
                                # Display progress updates
                                if event_type == 'connected':
                                    print(f"✅ Connected (session: {session_id[:8]}...)")
                                elif event_type == 'perfect_scene_start':
                                    print(f"🚀 {message_data.get('message', 'Starting...')}")
                                elif event_type == 'status':
                                    print(f"   {message_data.get('message', 'Processing...')}")
                                elif event_type == 'perfect_scene_completed':
                                    print(f"✅ {message_data.get('message', 'Completed!')}")
                                    if 'generation_time' in message_data:
                                        print(f"   ⏱️  Generation time: {message_data['generation_time']} seconds")
                                    # Store download URL for later download
                                    if 'download_url' in message_data:
                                        download_url[0] = message_data['download_url']
                                        print(f"   🔗 Download URL: {self.base_url}{message_data['download_url']}")
                                    generation_complete.set()
                                elif event_type == 'error':
                                    print(f"❌ Error: {message_data.get('message', 'Unknown error')}")
                                    generation_complete.set()
                                elif event_type == 'heartbeat':
                                    print(f"   💓 {message_data.get('message', 'Still processing...')}")
                                
                            except json.JSONDecodeError as e:
                                print(f"⚠️  Failed to parse progress event: {e}")
                            except Exception as e:
                                print(f"⚠️  Error processing progress: {e}")
            
            except requests.exceptions.RequestException as e:
                print(f"❌ Progress stream error: {e}")
                generation_complete.set()
        
        print(f"🔗 Starting progress listener for session: {session_id[:8]}...")
        thread = threading.Thread(target=listen_to_progress, daemon=True)
        thread.start()
        return thread

