"""City demographics and 360 entity workspace."""
from __future__ import annotations

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 sync_city_demographics(limit: int = 100) -> dict[str, Any]:
    cities = fetch_all(
        """SELECT DISTINCT city, province FROM supermarkets
           WHERE city IS NOT NULL AND city <> 'Onbekend'
           AND city NOT IN (SELECT city FROM city_demographics)
           LIMIT %s""",
        (limit,),
    )
    synced = 0
    for row in cities:
        pc_rows = fetch_all(
            "SELECT postcode FROM supermarkets WHERE city = %s AND postcode <> '0000AA' LIMIT 1",
            (row["city"],),
        )
        if not pc_rows:
            continue
        pd = pdok.lookup_postcode(pc_rows[0]["postcode"])
        if not pd or not pd.get("municipality_code"):
            continue
        stats = cbs.fetch_gemeente_stats(pd["municipality_code"])
        if not stats:
            continue
        rel = stats.get("religious_composition") or {}
        execute_returning(
            """INSERT INTO city_demographics (city, province, gemeente_code, population, households,
               avg_income, muslim_proxy_pct, data_source, last_updated)
               VALUES (%s,%s,%s,%s,%s,%s,%s,'cbs+pdok',NOW())
               ON CONFLICT (city, province) DO UPDATE SET
                 population=EXCLUDED.population, households=EXCLUDED.households,
                 avg_income=EXCLUDED.avg_income, muslim_proxy_pct=EXCLUDED.muslim_proxy_pct,
                 last_updated=NOW() RETURNING id""",
            (
                row["city"], row.get("province") or pd.get("province"),
                pd.get("municipality_code"), stats.get("population"), stats.get("households"),
                stats.get("avg_income"), rel.get("muslim_proxy_pct"),
            ),
        )
        synced += 1
    return {"synced": synced}


def get_city_context(city: str, province: Optional[str] = None) -> Optional[dict[str, Any]]:
    if province:
        row = fetch_one(
            "SELECT * FROM city_demographics WHERE city ILIKE %s AND province ILIKE %s",
            (city, province),
        )
    else:
        row = fetch_one("SELECT * FROM city_demographics WHERE city ILIKE %s LIMIT 1", (city,))
    if not row:
        return None
    stores = fetch_one(
        "SELECT COUNT(*) AS n FROM supermarkets WHERE city ILIKE %s", (city,)
    )
    out = dict(row)
    out["stores_in_city"] = int((stores or {}).get("n") or 0)
    return out


def get_store_360(supermarket_id: int) -> dict[str, Any]:
    store = fetch_one("SELECT * FROM supermarkets WHERE id = %s", (supermarket_id,))
    if not store:
        raise ValueError("Store not found")
    city_ctx = get_city_context(store["city"], store.get("province"))
    notes = fetch_all(
        "SELECT * FROM entity_notes WHERE entity_type='supermarket' AND entity_id=%s ORDER BY pinned DESC, created_at DESC",
        (supermarket_id,),
    )
    media = fetch_all(
        "SELECT * FROM entity_media WHERE entity_type='supermarket' AND entity_id=%s ORDER BY created_at DESC",
        (supermarket_id,),
    )
    milestones = fetch_all(
        "SELECT * FROM sales_milestones WHERE supermarket_id=%s ORDER BY sort_order, target_date NULLS LAST",
        (supermarket_id,),
    )
    ownership = fetch_all(
        """SELECT * FROM ownership_changes
           WHERE (entity_id=%s AND entity_type='supermarket') OR chain ILIKE %s
           ORDER BY effective_date DESC NULLS LAST LIMIT 10""",
        (supermarket_id, f"%{store['chain']}%"),
    )
    calendar = fetch_all(
        """SELECT * FROM calendar_events WHERE supermarket_id=%s OR (client_id=%s AND client_id IS NOT NULL)
           ORDER BY starts_at DESC LIMIT 10""",
        (supermarket_id, store.get("client_id")),
    )
    nearby_count = fetch_one(
        "SELECT COUNT(*) AS n FROM supermarkets WHERE city ILIKE %s AND id <> %s",
        (store["city"], supermarket_id),
    )
    area = fetch_one("SELECT * FROM area_analysis WHERE postcode = %s", (store.get("postcode"),))
    weather = fetch_all(
        "SELECT * FROM weather_data WHERE city ILIKE %s ORDER BY date DESC LIMIT 7",
        (f"%{store.get('city', '')}%",),
    )
    return {
        "store": dict(store),
        "city": city_ctx,
        "catchment": {
            "city_population": (city_ctx or {}).get("population"),
            "stores_in_city": int((nearby_count or {}).get("n") or 0),
            "gemeente_population": (area or {}).get("population"),
            "postcode_population_proxy": (area or {}).get("population"),
        },
        "notes": [dict(n) for n in notes],
        "media": [dict(m) for m in media],
        "milestones": [dict(m) for m in milestones],
        "ownership_changes": [dict(o) for o in ownership],
        "calendar": [dict(c) for c in calendar],
        "area_analysis": dict(area) if area else None,
        "weather": [dict(w) for w in weather],
    }


def add_note(entity_type: str, entity_id: int, body: str, title: Optional[str] = None, note_type: str = "general") -> dict[str, Any]:
    row = execute_returning(
        """INSERT INTO entity_notes (entity_type, entity_id, title, body, note_type)
           VALUES (%s,%s,%s,%s,%s) RETURNING *""",
        (entity_type, entity_id, title, body, note_type),
    )
    return dict(row or {})


def add_milestone(supermarket_id: int, title: str, milestone_type: str = "custom", **kwargs: Any) -> dict[str, Any]:
    row = execute_returning(
        """INSERT INTO sales_milestones (supermarket_id, client_id, deal_id, milestone_type, title,
           status, target_date, value_eur, notes, sort_order)
           VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) RETURNING *""",
        (
            supermarket_id, kwargs.get("client_id"), kwargs.get("deal_id"), milestone_type, title,
            kwargs.get("status", "pending"), kwargs.get("target_date"), kwargs.get("value_eur"),
            kwargs.get("notes"), kwargs.get("sort_order", 0),
        ),
    )
    return dict(row or {})


def add_ownership(**kwargs: Any) -> dict[str, Any]:
    row = execute_returning(
        """INSERT INTO ownership_changes (entity_type, entity_id, chain, previous_owner, new_owner,
           change_type, effective_date, source, notes)
           VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s) RETURNING *""",
        (
            kwargs.get("entity_type", "supermarket"), kwargs.get("entity_id"), kwargs.get("chain"),
            kwargs.get("previous_owner"), kwargs["new_owner"], kwargs.get("change_type", "acquisition"),
            kwargs.get("effective_date"), kwargs.get("source"), kwargs.get("notes"),
        ),
    )
    return dict(row or {})


def add_calendar_event(supermarket_id: int, title: str, starts_at: str, **kwargs: Any) -> dict[str, Any]:
    row = execute_returning(
        """INSERT INTO calendar_events (title, description, starts_at, ends_at, client_id, deal_id,
           supermarket_id, location, source)
           VALUES (%s,%s,%s,%s,%s,%s,%s,%s,'retail_360') RETURNING *""",
        (
            title, kwargs.get("description"), starts_at, kwargs.get("ends_at"),
            kwargs.get("client_id"), kwargs.get("deal_id"), supermarket_id,
            kwargs.get("location"),
        ),
    )
    return dict(row or {})


def register_media(entity_type: str, entity_id: int, filename: str, storage_path: str, content_type: str, caption: Optional[str] = None) -> dict[str, Any]:
    row = execute_returning(
        """INSERT INTO entity_media (entity_type, entity_id, filename, storage_path, content_type, caption)
           VALUES (%s,%s,%s,%s,%s,%s) RETURNING *""",
        (entity_type, entity_id, filename, storage_path, content_type, caption),
    )
    return dict(row or {})
