import json
import logging
from typing import Any, Dict, List, Optional, Union

import google.generativeai as genai

logger = logging.getLogger(__name__)


def estimate_from_comps(subject_sqft: int, comps: List[Dict[str, Any]]) -> Dict[str, Any]:
    """
    Compute estimate from comparables using median price-per-sqft
    """
    ppsf = [c["sale_price"] / c["sqft"]
            for c in comps or [] if c.get("sale_price") and c.get("sqft")]
    
    if not ppsf:
        return {"estimated_price": 0, "ppsf_avg": 0, "n_comps": 0}
    
    ppsf_sorted = sorted(ppsf)
    n = len(ppsf_sorted)
    mid = n // 2
    median_ppsf = ppsf_sorted[mid] if n % 2 else (ppsf_sorted[mid - 1] + ppsf_sorted[mid]) / 2
    est = int(round(median_ppsf * (subject_sqft or 0) / 1000.0) * 1000)
    
    return {"estimated_price": est, "ppsf_avg": median_ppsf, "n_comps": n}


def estimate_property_value(
    property_data: dict,
    gemini_client: Optional[Any] = None
) -> Union[Dict[str, Any], str]:
    """
    LLM-based property value estimation using Gemini.
    """
    if not gemini_client:
        return "Gemini estimation unavailable: GEMINI_API_KEY not set."
    
    address = f"{property_data.get('street','')}, {property_data.get('city','')}, " \
              f"{property_data.get('state','')} {property_data.get('zip_code','')}".strip()
    beds = property_data.get('beds') or "unknown"
    baths = property_data.get('baths') or "unknown"
    sqft = property_data.get('sqft') or "unknown"
    list_price = property_data.get('list_price')
    
    prompt = f"""You are a pricing bot. Return a compact JSON with:
- estimated_price (integer)
- note (<=6 words)
- confidence ("Low"|"Medium"|"High")
Context:
Address: {address}
Beds: {beds}
Baths: {baths}
Sqft: {sqft}
List price: {"${:,.0f}".format(list_price) if isinstance(list_price,(int,float)) else "Not listed"}
Return ONLY JSON.
"""
    
    def _call(max_tokens):
        return gemini_client.generate_content(
            contents=[{"role": "user", "parts": [{"text": prompt}]}],
            generation_config={
                "temperature": 0,
                "candidate_count": 1,
                "max_output_tokens": max_tokens,
                "response_mime_type": "application/json"
            }
        )

    def _extract_json(resp):
        for cand in getattr(resp, "candidates", []) or []:
            content = getattr(cand, "content", None)
            for part in getattr(content, "parts", []) or []:
                t = getattr(part, "text", None)
                if not t:
                    continue
                try:
                    return json.loads(t)
                except Exception:
                    continue
        return None

    try:
        resp = _call(80)
        obj = _extract_json(resp)
        if not obj:
            return {
                "estimated_price": int(list_price or 0),
                "note": "Estimated from inputs",
                "confidence": "Low"
            }
        
        est = int(round(int(obj.get("estimated_price", 0)) / 1000.0) * 1000)
        note = obj.get("note") or "—"
        conf = obj.get("confidence") if obj.get("confidence") in {"Low", "Medium", "High"} else "Low"
        
        return {"estimated_price": est, "note": note.strip()[:60], "confidence": conf}
    except Exception:
        est = int(round((property_data.get("list_price") or 0) / 1000.0) * 1000)
        return {"estimated_price": est, "note": "Fallback (LLM error)", "confidence": "Low"}
