"""Sub-agente: Valoración y mercado inmobiliario.

Fuentes: Zillow (scraping) + County Property Appraiser oficial de Florida.
Soporta todos los condados principales de Florida — se selecciona
automáticamente según el condado geocodificado.
"""

from __future__ import annotations

import re
import sys
import time
from pathlib import Path

import requests
from bs4 import BeautifulSoup
from data_fetchers.base import USER_AGENT, DEFAULT_TIMEOUT

_PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
if str(_PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(_PROJECT_ROOT))


# ── Mapa de condados → fetcher / sitio PA oficial ────────────────────────────
# Clave: fragmento del nombre del condado en minúsculas (como devuelve el geocoder)
# Valor: dict con 'fetcher' (función importable) o 'url' (sitio web PA para display)

COUNTY_PA_MAP = {
    # Condados con fetcher dedicado en data_fetchers/
    "broward":    {"fetcher": "data_fetchers.pa_broward:fetch_pa_broward",
                   "name": "Broward County PA", "site": "https://bcpa.net"},
    "miami-dade": {"fetcher": "data_fetchers.pa_miami_dade:fetch_pa_miami_dade",
                   "name": "Miami-Dade PA", "site": "https://www.miamidade.gov/Apps/PA/propertysearch"},
    "palm beach": {"fetcher": "data_fetchers.pa_palm_beach:fetch_pa_palm_beach",
                   "name": "Palm Beach County PA", "site": "https://pbcpao.gov"},
    "duval":      {"fetcher": "data_fetchers.pa_duval:fetch_pa_duval",
                   "name": "Duval County PA (Jacksonville)", "site": "https://www.coj.net/departments/property-appraiser"},

    # Condados con sitio PA oficial (scraping genérico o referencia)
    "st. johns":  {"site": "https://www.sjcpa.us",
                   "name": "St. Johns County PA (St. Augustine)"},
    "saint johns":{"site": "https://www.sjcpa.us",
                   "name": "St. Johns County PA (St. Augustine)"},
    "volusia":    {"site": "https://vcpa.volusia.org",
                   "name": "Volusia County PA (Daytona Beach)"},
    "orange":     {"site": "https://www.ocpafl.org",
                   "name": "Orange County PA (Orlando)"},
    "hillsborough":{"site": "https://www.hcpafl.org",
                    "name": "Hillsborough County PA (Tampa)"},
    "pinellas":   {"site": "https://www.pcpao.gov",
                   "name": "Pinellas County PA (St. Petersburg/Clearwater)"},
    "seminole":   {"site": "https://www.scpafl.org",
                   "name": "Seminole County PA (Sanford/Altamonte)"},
    "osceola":    {"site": "https://www.property-appraiser.org",
                   "name": "Osceola County PA (Kissimmee)"},
    "brevard":    {"site": "https://www.bcpao.us",
                   "name": "Brevard County PA (Melbourne/Cocoa)"},
    "indian river":{"site": "https://www.ircpa.org",
                    "name": "Indian River County PA (Vero Beach)"},
    "martin":     {"site": "https://www.pa.martin.fl.us",
                   "name": "Martin County PA (Stuart/Hobe Sound)"},
    "st. lucie":  {"site": "https://www.paslc.gov",
                   "name": "St. Lucie County PA (Port St. Lucie/Fort Pierce)"},
    "saint lucie":{"site": "https://www.paslc.gov",
                   "name": "St. Lucie County PA"},
    "lee":        {"site": "https://www.leepa.org",
                   "name": "Lee County PA (Fort Myers/Cape Coral)"},
    "collier":    {"site": "https://www.collierappraiser.com",
                   "name": "Collier County PA (Naples/Marco Island)"},
    "charlotte":  {"site": "https://www.ccappraiser.com",
                   "name": "Charlotte County PA (Port Charlotte/Punta Gorda)"},
    "sarasota":   {"site": "https://www.sc-pa.com",
                   "name": "Sarasota County PA"},
    "manatee":    {"site": "https://www.manateepao.gov",
                   "name": "Manatee County PA (Bradenton)"},
    "polk":       {"site": "https://www.polkpa.org",
                   "name": "Polk County PA (Lakeland/Winter Haven)"},
    "pasco":      {"site": "https://www.pascopa.com",
                   "name": "Pasco County PA (New Port Richey/Wesley Chapel)"},
    "hernando":   {"site": "https://www.hernandopa-fl.us",
                   "name": "Hernando County PA (Spring Hill/Brooksville)"},
    "citrus":     {"site": "https://www.citruspa.org",
                   "name": "Citrus County PA (Crystal River/Inverness)"},
    "marion":     {"site": "https://www.pa.marion.fl.us",
                   "name": "Marion County PA (Ocala)"},
    "alachua":    {"site": "https://www.acpafl.org",
                   "name": "Alachua County PA (Gainesville)"},
    "putnam":     {"site": "https://www.putnam-fl.com/pa",
                   "name": "Putnam County PA (Palatka)"},
    "flagler":    {"site": "https://www.flaglerpa.com",
                   "name": "Flagler County PA (Palm Coast/Flagler Beach)"},
    "clay":       {"site": "https://www.ccpao.com",
                   "name": "Clay County PA (Fleming Island/Orange Park)"},
    "nassau":     {"site": "https://www.nassauflpa.com",
                   "name": "Nassau County PA (Fernandina Beach/Yulee)"},
    "baker":      {"site": "https://www.bakerpa.com",
                   "name": "Baker County PA (Macclenny)"},
    "columbia":   {"site": "https://www.columbiapafl.com",
                   "name": "Columbia County PA (Lake City)"},
    "leon":       {"site": "https://www.leonpa.org",
                   "name": "Leon County PA (Tallahassee)"},
    "escambia":   {"site": "https://www.escpa.org",
                   "name": "Escambia County PA (Pensacola)"},
    "santa rosa": {"site": "https://www.srcpa.org",
                   "name": "Santa Rosa County PA (Milton/Gulf Breeze)"},
    "okaloosa":   {"site": "https://www.okaloosapa.com",
                   "name": "Okaloosa County PA (Fort Walton Beach/Destin)"},
    "walton":     {"site": "https://www.waltonpa.com",
                   "name": "Walton County PA (Destin/30A/DeFuniak Springs)"},
    "bay":        {"site": "https://www.baycopa.com",
                   "name": "Bay County PA (Panama City)"},
    "monroe":     {"site": "https://www.mcpafl.org",
                   "name": "Monroe County PA (Florida Keys)"},
    "lake":       {"site": "https://www.lakepa.org",
                   "name": "Lake County PA (Leesburg/Tavares/Mount Dora)"},
    "sumter":     {"site": "https://www.sumterpa.com",
                   "name": "Sumter County PA (The Villages/Bushnell)"},
}


def _match_county(county: str) -> dict | None:
    """Encuentra el PA info para un condado dado."""
    c = county.lower().strip()
    # Coincidencia exacta primero
    if c in COUNTY_PA_MAP:
        return COUNTY_PA_MAP[c]
    # Coincidencia parcial
    for key, val in COUNTY_PA_MAP.items():
        if key in c or c in key:
            return val
    return None


def run(lat: float, lon: float, address: str, county: str = "") -> dict:
    """Recopila datos de valoración inmobiliaria."""
    result = {
        "estimated_value": None,
        "price_per_sqft": None,
        "appreciation_1y": None,
        "appreciation_3y": None,
        "days_on_market": None,
        "median_list_price": None,
        "inventory": None,
        "county_assessed_value": None,
        "county_market_value": None,
        "pa_site": None,
        "pa_name": None,
        "sources": [],
        "errors": [],
    }

    # --- Zillow ---
    try:
        z = _zillow_neighborhood(lat, lon, address)
        result.update({k: v for k, v in z.items() if v is not None})
        result["sources"].append("Zillow")
    except Exception as e:
        result["errors"].append(f"Zillow: {e}")

    # --- County Property Appraiser ---
    pa_info = _match_county(county)
    if pa_info:
        result["pa_name"] = pa_info.get("name", "")
        result["pa_site"] = pa_info.get("site", "")

        fetcher_ref = pa_info.get("fetcher")
        if fetcher_ref:
            try:
                module_path, func_name = fetcher_ref.split(":")
                import importlib
                mod = importlib.import_module(module_path)
                fetch_fn = getattr(mod, func_name)
                pa = fetch_fn(address)
                if pa:
                    result["county_assessed_value"] = pa.get("assessed_value")
                    result["county_market_value"]   = pa.get("market_value")
                    result["sources"].append(pa_info["name"])
            except Exception as e:
                result["errors"].append(f"{pa_info.get('name','PA')}: {e}")
        else:
            # Sin fetcher dedicado — registrar el sitio como referencia
            result["sources"].append(f"{pa_info['name']} (referencia)")
    else:
        result["errors"].append(
            f"County Appraiser no mapeado para: '{county}'. "
            "Consulta manualemente en floridapropertytax.org"
        )

    return result


def _zillow_neighborhood(lat: float, lon: float, address: str) -> dict:
    """Scraping básico de Zillow para datos del vecindario."""
    # Buscar ZIP de la dirección
    zip_m = re.search(r"\b(\d{5})\b", address)
    zip_code = zip_m.group(1) if zip_m else ""

    if not zip_code:
        raise ValueError("No se encontró ZIP code en la dirección")

    url = f"https://www.zillow.com/homes/{zip_code}_rb/"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    }
    time.sleep(3)  # rate limiting
    r = requests.get(url, headers=headers, timeout=DEFAULT_TIMEOUT)
    r.raise_for_status()

    soup = BeautifulSoup(r.text, "html.parser")

    # Extraer datos estructurados si están disponibles (script tags con JSON)
    result = {}
    for script in soup.find_all("script", type="application/json"):
        try:
            import json
            data = json.loads(script.string or "")
            # Buscar datos de precio en la estructura JSON de Zillow
            if isinstance(data, dict):
                props = data.get("cat1", {}).get("searchResults", {}).get("listResults", [])
                if props:
                    prices = [p.get("price", 0) for p in props if p.get("price")]
                    if prices:
                        result["median_list_price"] = sorted(prices)[len(prices) // 2]
                    sqfts = [p.get("price", 0) / p.get("area", 1)
                             for p in props if p.get("price") and p.get("area")]
                    if sqfts:
                        result["price_per_sqft"] = round(sum(sqfts) / len(sqfts))
                    doms = [p.get("daysOnZillow", 0) for p in props if p.get("daysOnZillow")]
                    if doms:
                        result["days_on_market"] = round(sum(doms) / len(doms))
                    result["inventory"] = len(props)
        except Exception:
            continue

    return result


def score(data: dict) -> int:
    """Calcula score 0-100 de mercado inmobiliario."""
    if not data:
        return 50

    s = 50  # base

    # Apreciación 1 año (si disponible)
    app1 = data.get("appreciation_1y")
    if app1 is not None:
        if app1 >= 10:
            s += 20
        elif app1 >= 5:
            s += 12
        elif app1 >= 0:
            s += 5
        else:
            s -= 10

    # Días en mercado (menos días = mercado más activo)
    dom = data.get("days_on_market")
    if dom is not None:
        if dom <= 20:
            s += 15
        elif dom <= 40:
            s += 8
        elif dom <= 60:
            s += 0
        else:
            s -= 10

    # Precio por sqft como indicador de demanda
    ppsf = data.get("price_per_sqft")
    if ppsf is not None:
        if ppsf >= 300:
            s += 10
        elif ppsf >= 200:
            s += 5

    return min(100, max(0, s))
