"""Per-store allocation (spec §1 / Phase 4).

Retail is the only per-store channel (web + wholesale are central). Stores mostly
share a SKU's demand shape scaled by store size, so we don't model each store
independently — we forecast the region's retail (engine) and ALLOCATE it down to
that region's stores by recency-weighted share. New stores get their recent
share; closed stores (no recent activity) decay to ~0.
"""
from __future__ import annotations

from collections import defaultdict

import numpy as np


def store_shares(store_qty: dict, window: int = 26, decay: float = 0.95) -> dict:
    """{store_id: weekly array} -> {store_id: share} (recency-weighted, sums to 1
    within the set). Equal split as a fallback when there's no recent volume."""
    keys = list(store_qty)
    if not keys:
        return {}
    w = np.array([decay ** i for i in range(window)][::-1])
    rec = {}
    for s in keys:
        q = np.asarray(store_qty[s], dtype=float)[-window:]
        if len(q) < window:
            q = np.pad(q, (window - len(q), 0))
        rec[s] = float(np.average(q, weights=w))
    tot = sum(rec.values())
    if tot <= 0:
        return {s: 1.0 / len(keys) for s in keys}
    return {s: v / tot for s, v in rec.items()}


def allocate(total, shares: dict) -> dict:
    """total (scalar 13wk or array[h]) split by shares -> {store_id: value}."""
    return {s: np.asarray(total) * sh for s, sh in shares.items()}


def allocate_retail_to_stores(retail_by_region: dict, stores: dict,
                              window: int = 26) -> dict:
    """retail_by_region: {region: total13}. stores: {store_id: {'name','region',
    'qty'}} from data.load_store_retail. Returns {store_id: {'name','region',
    'total13','share'}} — each region's retail split across its own stores."""
    by_region: dict[str, dict] = defaultdict(dict)
    meta = {}
    for sid, info in stores.items():
        by_region[info["region"]][sid] = info["qty"]
        meta[sid] = info

    out = {}
    for region, region_total in retail_by_region.items():
        shares = store_shares(by_region.get(region, {}), window=window)
        for sid, share in shares.items():
            out[sid] = {"name": meta[sid]["name"], "region": region,
                        "share": round(share, 4),
                        "total13": float(np.asarray(region_total).sum() * share)
                        if hasattr(region_total, "__len__")
                        else float(region_total) * share}
    return out
