"""Halal market opportunity scoring for retail locations."""
from __future__ import annotations

from typing import Any

from app.db import execute, fetch_all, fetch_one, json_param


def compute_all_scores(limit: int = 5000) -> dict[str, Any]:
    rows = fetch_all(
        """
        SELECT s.id, s.chain, s.city, s.postcode, s.halal_certified, s.has_halal_section,
               s.partnership_status, a.population, a.avg_income,
               (a.religious_composition->>'muslim_proxy_pct')::float AS muslim_pct,
               (a.ethnic_composition->>'niet_westers_pct')::float AS niet_westers_pct
        FROM supermarkets s
        LEFT JOIN area_analysis a ON a.postcode = s.postcode
        WHERE s.postcode <> '0000AA'
        LIMIT %s
        """,
        (limit,),
    )
    computed = 0
    for r in rows:
        muslim = float(r.get("muslim_pct") or 0)
        niet_w = float(r.get("niet_westers_pct") or 0)
        pop = int(r.get("population") or 0)
        income = float(r.get("avg_income") or 0)

        halal_gap = 0.0
        if not r.get("halal_certified") and not r.get("has_halal_section"):
            halal_gap = min(100, muslim * 1.5 + niet_w * 0.5)
        elif r.get("has_halal_section") and not r.get("halal_certified"):
            halal_gap = min(80, muslim * 0.8)

        market_potential = 0.0
        if pop > 0:
            market_potential += min(40, pop / 25000)
        if income > 0:
            market_potential += min(30, income / 1500)
        market_potential += min(30, muslim * 0.4)

        partnership_bonus = 15 if r.get("partnership_status") == "active" else 0
        halal_opp = round(min(100, halal_gap + market_potential * 0.3), 1)
        market_score = round(min(100, market_potential + partnership_bonus), 1)

        factors = {
            "muslim_proxy_pct": muslim,
            "niet_westers_pct": niet_w,
            "population": pop,
            "avg_income": income,
            "halal_gap": round(halal_gap, 1),
            "has_halal_section": bool(r.get("has_halal_section")),
            "halal_certified": bool(r.get("halal_certified")),
            "partnership_status": r.get("partnership_status"),
        }
        execute(
            """
            INSERT INTO retail_opportunity_scores (supermarket_id, halal_opportunity_score,
                market_potential_score, factors, computed_at)
            VALUES (%s, %s, %s, %s, NOW())
            ON CONFLICT (supermarket_id) DO UPDATE SET
                halal_opportunity_score = EXCLUDED.halal_opportunity_score,
                market_potential_score = EXCLUDED.market_potential_score,
                factors = EXCLUDED.factors,
                computed_at = NOW()
            """,
            (r["id"], halal_opp, market_score, json_param(factors)),
        )
        execute(
            "UPDATE supermarkets SET halal_opportunity_score = %s WHERE id = %s",
            (halal_opp, r["id"]),
        )
        computed += 1
    return {"computed": computed}


def top_opportunities(
    limit: int = 50,
    min_score: float = 30,
    chain: str | None = None,
    province: str | None = None,
) -> list[dict[str, Any]]:
    clauses = ["ros.halal_opportunity_score >= %s"]
    params: list[Any] = [min_score]
    if chain:
        clauses.append("s.chain ILIKE %s")
        params.append(f"%{chain}%")
    if province:
        clauses.append("s.province ILIKE %s")
        params.append(f"%{province}%")
    where = " AND ".join(clauses)
    return fetch_all(
        f"""
        SELECT s.id, s.name, s.chain, s.city, s.province, s.postcode,
               s.partnership_status, s.halal_certified, s.has_halal_section,
               ros.halal_opportunity_score, ros.market_potential_score, ros.factors,
               a.population, a.avg_income,
               (a.religious_composition->>'muslim_proxy_pct')::float AS muslim_proxy_pct
        FROM retail_opportunity_scores ros
        JOIN supermarkets s ON s.id = ros.supermarket_id
        LEFT JOIN area_analysis a ON a.postcode = s.postcode
        WHERE {where}
        ORDER BY ros.halal_opportunity_score DESC
        LIMIT %s
        """,
        tuple(params + [limit]),
    )
