"""
Zillow Property Details Module - Scrapeak API

This module provides functions to fetch detailed property information from Zillow using the Scrapeak API.
"""

import requests
import logging
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Dict, List, Union


def clean_property_details_data(property_data):
    """Clean and extract essential fields from property details data"""
    try:
        p = property_data
        
        # Extract nested data structures
        reso_facts = p.get("resoFacts", {})
        home_info = p.get("homeInfo", {})
        address = p.get("address", {})
        price_history = p.get("priceHistory", [])
        responsive_photos = p.get("responsivePhotos", [])
        
        # Get price change info from price history
        price_change = None
        price_change_date = None
        if price_history and len(price_history) > 1:
            latest_price = price_history[0].get("price", 0)
            previous_price = price_history[1].get("price", 0)
            if latest_price != previous_price:
                price_change = latest_price - previous_price
                price_change_date = price_history[0].get("date", "")
        
        # Extract photo URLs
        photo_urls = []
        if responsive_photos:
            photo_urls = [photo.get("url", "") for photo in responsive_photos[:5]]  # First 5 photos
        
        return {
            # BASIC IDENTIFICATION
            "zpid": p.get("zpid"),
            "streetAddress": address.get("streetAddress"),
            "city": address.get("city"),
            "state": address.get("state"),
            "zipcode": address.get("zipcode"),
            "latitude": address.get("latitude"),
            "longitude": address.get("longitude"),
            
            # PRICING & FINANCIAL
            "price": p.get("price"),
            "priceChange": price_change,
            "priceChangeDate": price_change_date,
            "pricePerSquareFoot": reso_facts.get("pricePerSquareFoot"),
            "zestimate": home_info.get("zestimate"),
            "zestimateLowPercent": home_info.get("zestimateLowPercent"),
            "zestimateHighPercent": home_info.get("zestimateHighPercent"),
            "rentZestimate": home_info.get("rentZestimate"),
            "taxAnnualAmount": home_info.get("taxAnnualAmount"),
            "taxAssessedValue": home_info.get("taxAssessedValue"),
            "propertyTaxRate": home_info.get("propertyTaxRate"),
            
            # PROPERTY SPECIFICATIONS
            "bedrooms": reso_facts.get("bedrooms"),
            "bathrooms": reso_facts.get("bathrooms"),
            "bathroomsFull": reso_facts.get("bathroomsFull"),
            "bathroomsHalf": reso_facts.get("bathroomsHalf"),
            "livingArea": reso_facts.get("aboveGradeFinishedArea"),
            "lotSize": reso_facts.get("lotSize"),
            "yearBuilt": reso_facts.get("yearBuilt"),
            "homeType": reso_facts.get("homeType"),
            "architecturalStyle": reso_facts.get("architecturalStyle"),
            "levels": reso_facts.get("levels"),
            "basement": reso_facts.get("basement"),
            "garageParkingCapacity": reso_facts.get("garageParkingCapacity"),
            "parkingCapacity": reso_facts.get("parkingCapacity"),
            
            # FEATURES & AMENITIES
            "heating": reso_facts.get("heating"),
            "cooling": reso_facts.get("cooling"),
            "fireplaceFeatures": reso_facts.get("fireplaceFeatures"),
            "appliances": reso_facts.get("appliances"),
            "flooring": reso_facts.get("flooring"),
            "roofType": reso_facts.get("roofType"),
            "constructionMaterials": reso_facts.get("constructionMaterials"),
            "lotFeatures": reso_facts.get("lotFeatures"),
            "parkingFeatures": reso_facts.get("parkingFeatures"),
            "patioAndPorchFeatures": reso_facts.get("patioAndPorchFeatures"),
            
            # LOCATION & ZONING
            "zoning": p.get("zoning"),
            "zoningDescription": p.get("zoningDescription"),
            "neighborhood": p.get("neighborhood"),
            "subdivision": p.get("subdivision"),
            
            # SCHOOLS
            "elementarySchool": p.get("elementarySchool"),
            "elementarySchoolDistrict": p.get("elementarySchoolDistrict"),
            "middleOrJuniorSchool": p.get("middleOrJuniorSchool"),
            "middleOrJuniorSchoolDistrict": p.get("middleOrJuniorSchoolDistrict"),
            "highSchool": p.get("highSchool"),
            "highSchoolDistrict": p.get("highSchoolDistrict"),
            
            # PROPERTY DESCRIPTION & MEDIA
            "description": p.get("description"),
            "photoCount": len(responsive_photos) if responsive_photos else 0,
            "photoUrls": ",".join(photo_urls) if photo_urls else None,
            
            # LISTING & AGENT INFO
            "agentName": p.get("agentName"),
            "agentPhoneNumber": p.get("agentPhoneNumber"),
            "brokerName": p.get("brokerName"),
            "brokerPhoneNumber": p.get("brokerPhoneNumber"),
            "listingTerms": p.get("listingTerms"),
            "onMarketDate": p.get("onMarketDate"),
            "daysOnZillow": p.get("daysOnZillow")
        }
    except Exception as e:
        # Return minimal data if cleaning fails
        return {
            "zpid": p.get("zpid"),
            "streetAddress": p.get("address", {}).get("streetAddress"),
            "city": p.get("address", {}).get("city"),
            "state": p.get("address", {}).get("state"),
            "price": p.get("price"),
            "bedrooms": p.get("resoFacts", {}).get("bedrooms"),
            "bathrooms": p.get("resoFacts", {}).get("bathrooms"),
            "livingArea": p.get("resoFacts", {}).get("aboveGradeFinishedArea")
        }


def get_property_details(
    api_key: str,
    zpids: Union[str, List[str]],
    batch_size: int = 2,
    clean_data: bool = True,
    enable_logging: bool = False
) -> Dict:
    """
    Get detailed property information for one or more ZPIDs using Scrapeak API
    
    Parameters:
    -----------
    api_key : str
        Your Scrapeak API key
    zpids : str or list of str
        Single ZPID string or list of ZPIDs to get details for
    batch_size : int, optional
        Number of concurrent requests per second (default: 2)
    clean_data : bool, optional
        If True, returns cleaned data with essential fields only; if False, returns raw data (default: True)
    enable_logging : bool, optional
        If True, enables progress logging for multiple ZPIDs (default: False)
    
    Returns:
    --------
    dict
        Dictionary containing:
        - data: List of property details (one per ZPID)
        - credits: API credit usage information
        - summary: Summary statistics
        
    Example:
    --------
    >>> # Single property
    >>> details = get_property_details(api_key, "34648268")
    >>> 
    >>> # Multiple properties
    >>> zpids = ["34648268", "121349556", "45037932"]
    >>> details = get_property_details(api_key, zpids, enable_logging=True)
    >>> 
    >>> # From listings data
    >>> listings = get_zillow_listings(api_key, url)
    >>> zpids = [prop['zpid'] for prop in listings['data']]
    >>> details = get_property_details(api_key, zpids)
    """
    
    # Normalize input to list
    if isinstance(zpids, str):
        zpids = [zpids]
    
    if not zpids:
        return {"data": [], "credits": {"used": 0, "remaining": 0}, "summary": {"total": 0, "successful": 0, "failed": 0}}
    
    api_url = "https://app.scrapeak.com/v1/scrapers/zillow/property"
    all_properties = []
    total_used_credits = 0
    successful_count = 0
    failed_count = 0
    
    # Setup logging if enabled
    if enable_logging:
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            datefmt='%H:%M:%S'
        )
        logger = logging.getLogger(__name__)
    else:
        logger = None
    
    if logger:
        logger.info(f"Fetching property details for {len(zpids)} properties...")
    
    def fetch_single_property(zpid):
        """Fetch a single property by ZPID"""
        try:
            params = {"api_key": api_key, "zpid": str(zpid)}
            response = requests.get(api_url, params=params)
            
            if response.status_code == 200:
                response_data = response.json()
                
                if response_data.get('is_success', False):
                    property_data = response_data.get('data', {})
                    property_data['zpid'] = str(zpid)
                    credits_used = response_data.get('info', {}).get('used_credits', 0)
                    return {
                        'success': True,
                        'data': property_data,
                        'credits': credits_used,
                        'zpid': str(zpid)
                    }
                else:
                    return {
                        'success': False,
                        'error': f"API returned unsuccessful response for ZPID {zpid}",
                        'zpid': str(zpid)
                    }
            else:
                return {
                    'success': False,
                    'error': f"HTTP error {response.status_code} for ZPID {zpid}",
                    'zpid': str(zpid)
                }
        except Exception as e:
            return {
                'success': False,
                'error': f"Exception fetching ZPID {zpid}: {str(e)}",
                'zpid': str(zpid)
            }
    
    # Process with continuous rate limiting using a single executor
    processed_count = 0
    all_futures = []
    
    # Use a single executor with higher max_workers for better concurrency
    max_workers = min(batch_size * 3, len(zpids))  # Allow more concurrent workers
    
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        # Submit all requests with 1-second intervals between batches
        for i, zpid in enumerate(zpids):
            # Calculate which batch this request belongs to
            batch_num = i // batch_size
            
            # Submit the request immediately
            future = executor.submit(fetch_single_property, zpid)
            all_futures.append(future)
            
            # Rate limiting: wait 1 second between batches
            if (i + 1) % batch_size == 0 and i < len(zpids) - 1:
                time.sleep(1.0)
        
        # Process all results as they complete
        for future in as_completed(all_futures):
            result = future.result()
            processed_count += 1
            
            # Log progress every 10 properties or for single property
            if logger and (processed_count % 10 == 0 or len(zpids) == 1 or processed_count == len(zpids)):
                logger.info(f"Processing property {processed_count}/{len(zpids)}")
            
            if result['success']:
                # Apply data cleaning if requested
                if clean_data:
                    cleaned_data = clean_property_details_data(result['data'])
                    all_properties.append(cleaned_data)
                else:
                    all_properties.append(result['data'])
                total_used_credits += result['credits']
                successful_count += 1
            else:
                failed_count += 1
                if logger:
                    logger.warning(result['error'])
    
    if logger:
        logger.info(f"Completed: {successful_count} successful, {failed_count} failed")
    
    return {
        "data": all_properties,
        "credits": {
            "used": total_used_credits,
            "remaining": 0  # Would need to track this from last response
        },
        "summary": {
            "total": len(zpids),
            "successful": successful_count,
            "failed": failed_count
        }
    }


def get_property_details_summary(details: Dict) -> Dict:
    """
    Get a structured summary of the property details data
    
    Parameters:
    -----------
    details : dict
        The response from get_property_details function
    
    Returns:
    --------
    dict
        Structured summary with statistics and sample data
    """
    if not details or not details.get('data'):
        return {"error": "No property details data available"}
    
    data = details.get('data', [])
    summary = details.get('summary', {})
    credits = details.get('credits', {})
    
    # Extract sample property info
    sample_properties = []
    for prop in data[:3]:  # First 3 properties
        sample_properties.append({
            "zpid": prop.get('zpid', 'N/A'),
            "address": f"{prop.get('streetAddress', '')} {prop.get('city', '')} {prop.get('state', '')} {prop.get('zipcode', '')}".strip(),
            "price": prop.get('price', 'N/A'),
            "bedrooms": prop.get('bedrooms', 'N/A'),
            "bathrooms": prop.get('bathrooms', 'N/A'),
            "living_area": prop.get('livingArea', 'N/A')
        })
    
    return {
        "summary": {
            "total_requested": summary.get('total', 0),
            "successful": summary.get('successful', 0),
            "failed": summary.get('failed', 0),
            "success_rate": f"{(summary.get('successful', 0) / max(summary.get('total', 1), 1)) * 100:.1f}%"
        },
        "credits": {
            "used": credits.get('used', 0),
            "remaining": credits.get('remaining', 0)
        },
        "sample_properties": sample_properties
    }
