"""Enrich supermarket postcodes with PDOK geocoding + CBS demografie."""
from __future__ import annotations

import time
from typing import Any, Optional

from app.connectors import cbs, pdok
from app.db import execute, execute_returning, fetch_all, fetch_one, json_param


def _postcodes_to_enrich(limit: int = 100, offset: int = 0) -> list[str]:
    rows = fetch_all(
        """
        SELECT DISTINCT s.postcode
        FROM supermarkets s
        LEFT JOIN area_analysis a ON a.postcode = s.postcode
        WHERE s.postcode IS NOT NULL
          AND s.postcode <> '0000AA'
          AND a.id IS NULL
        ORDER BY s.postcode
        LIMIT %s OFFSET %s
        """,
        (limit, offset),
    )
    return [r["postcode"] for r in rows]


def enrich_postcode(postcode: str) -> dict[str, Any]:
    pc = pdok.normalize_postcode(postcode)
    pdok_data = pdok.lookup_postcode(pc)
    if not pdok_data:
        return {"postcode": pc, "status": "pdok_not_found"}

    gm_code = pdok_data.get("municipality_code")
    cbs_data = cbs.fetch_gemeente_stats(gm_code) if gm_code else None
    if not cbs_data:
        return {"postcode": pc, "status": "cbs_not_found", "pdok": pdok_data}

    religious = cbs_data.get("religious_composition") or {}
    row = execute_returning(
        """
        INSERT INTO area_analysis (
            postcode, city, population, households, avg_household_size,
            avg_income, median_income, education_level, ethnic_composition,
            religious_composition, unemployment_rate, housing_type, car_ownership,
            data_source, last_updated
        ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,NOW())
        ON CONFLICT (postcode) DO UPDATE SET
            city = EXCLUDED.city,
            population = EXCLUDED.population,
            households = EXCLUDED.households,
            avg_household_size = EXCLUDED.avg_household_size,
            avg_income = EXCLUDED.avg_income,
            median_income = EXCLUDED.median_income,
            education_level = EXCLUDED.education_level,
            ethnic_composition = EXCLUDED.ethnic_composition,
            religious_composition = EXCLUDED.religious_composition,
            housing_type = EXCLUDED.housing_type,
            car_ownership = EXCLUDED.car_ownership,
            data_source = EXCLUDED.data_source,
            last_updated = NOW()
        RETURNING id, postcode
        """,
        (
            pc,
            pdok_data.get("city") or cbs_data.get("city"),
            cbs_data.get("population"),
            cbs_data.get("households"),
            cbs_data.get("avg_household_size"),
            cbs_data.get("avg_income"),
            cbs_data.get("median_income"),
            json_param(cbs_data.get("education_level")),
            json_param(cbs_data.get("ethnic_composition")),
            json_param(religious),
            cbs_data.get("unemployment_rate"),
            json_param(cbs_data.get("housing_type")),
            cbs_data.get("car_ownership"),
            f"cbs+pdok ({cbs_data.get('data_granularity', 'gemeente')})",
        ),
    )

    execute(
        """
        UPDATE supermarkets SET
            city = COALESCE(NULLIF(city, 'Onbekend'), %s),
            province = COALESCE(province, %s),
            latitude = COALESCE(latitude, %s),
            longitude = COALESCE(longitude, %s),
            last_updated = NOW()
        WHERE postcode = %s AND (
            city = 'Onbekend' OR province IS NULL OR latitude IS NULL OR longitude IS NULL
        )
        """,
        (
            pdok_data.get("city"),
            pdok_data.get("province"),
            pdok_data.get("latitude"),
            pdok_data.get("longitude"),
            pc,
        ),
    )
    return {
        "postcode": pc,
        "status": "ok",
        "area_id": row["id"] if row else None,
        "municipality": pdok_data.get("municipality"),
        "population": cbs_data.get("population"),
        "muslim_proxy_pct": religious.get("muslim_proxy_pct"),
    }


def enrich_batch(limit: int = 50, offset: int = 0, delay_sec: float = 0.15) -> dict[str, Any]:
    postcodes = _postcodes_to_enrich(limit, offset)
    results: list[dict[str, Any]] = []
    ok = failed = 0
    for pc in postcodes:
        try:
            result = enrich_postcode(pc)
            results.append(result)
            if result.get("status") == "ok":
                ok += 1
            else:
                failed += 1
        except Exception as exc:  # noqa: BLE001
            results.append({"postcode": pc, "status": "error", "error": str(exc)})
            failed += 1
        time.sleep(delay_sec)

    remaining = fetch_one(
        """
        SELECT COUNT(DISTINCT s.postcode) AS n
        FROM supermarkets s
        LEFT JOIN area_analysis a ON a.postcode = s.postcode
        WHERE s.postcode <> '0000AA' AND a.id IS NULL
        """
    )
    return {
        "processed": len(postcodes),
        "ok": ok,
        "failed": failed,
        "remaining": int((remaining or {}).get("n") or 0),
        "results": results[:20],
    }


def enrichment_status() -> dict[str, Any]:
    total_pc = fetch_one(
        "SELECT COUNT(DISTINCT postcode) AS n FROM supermarkets WHERE postcode <> '0000AA'"
    )
    enriched = fetch_one("SELECT COUNT(*) AS n FROM area_analysis")
    providers = fetch_all(
        "SELECT name, provider_type, last_fetch_at, last_status, is_active FROM data_providers ORDER BY name"
    )
    return {
        "unique_postcodes": int((total_pc or {}).get("n") or 0),
        "enriched_postcodes": int((enriched or {}).get("n") or 0),
        "data_providers": [dict(p) for p in providers],
    }
