from __future__ import annotations

import time
import re
from typing import Dict, List, Tuple, Optional
from urllib.parse import urlparse, urljoin

from shared.config import config
from . import db_backend as cb
from .blacklist.category import is_category_blocked  # Reverse map: slug -> label

# ------------------ Caches ------------------
_nav_cache: Dict = {}
_nav_cache_ts: float = 0.0
_nav_ttl_seconds = 60 * 60 * 6  # 6 hours


def _now() -> float:
    try:
        return now()  # type: ignore[name-defined]
    except Exception:
        return time.time()


def extract_sub_slug(href: str, top_slug: str) -> Optional[str]:
    p = urlparse(href)
    parts = [x for x in (p.path or "").split("/") if x]
    if len(parts) >= 2 and parts[0].lower() == top_slug.lower():
        sub = parts[1]
        if sub.lower().endswith((".html", ".htm")):
            sub = re.sub(r"\.(html?|HTML?)$", "", sub)
        return sub
    return None


def group_by_category(slug_to_links: Dict[str, List[Tuple[str, str]]]) -> Dict[str, Dict]:
    nav = {"cats": {}}
    for label, slug in config()["categories"]["allow"].items():
        top_href = urljoin(config()["base_url"], f"/{slug}")
        subs = []
        for text, href in slug_to_links.get(slug, []):
            sub_slug = extract_sub_slug(href, slug)
            if sub_slug:
                subs.append({
                    "name": text,
                    "href": href,
                    "slug": sub_slug,
                    # no count here yet in this path
                })
        subs.sort(key=lambda x: x["name"].lower())
        nav["cats"][label] = {"href": top_href, "slug": slug, "subs": subs}
    nav = _apply_category_blacklist(nav)
    return nav


async def get_nav(session, market_id=None) -> Dict[str, Dict]:
    """
    Return navigation structure; annotate each sub with product counts.
    Uses snapshot for offline behaviour.
    """
    global _nav_cache, _nav_cache_ts
    now_ts = _now()

    # load from snapshot
    nav = await cb.db_nav(session, market_id=market_id)

    # inject counts for each subcategory (and for top-level too if you like)
    for label, cat in (nav.get("cats") or {}).items():
        top_slug = cat.get("slug")
        if not top_slug:
            continue


        # Counts for subs
        new_subs = []
        for s in cat.get("subs", []):
            s.get("slug")
            #if not sub_slug:
            #    s_count = 0
            #else:
            #    s_count = await cb.db_count_products_in_sub(session,top_slug, sub_slug)
            #print('sub', s_count)
            new_subs.append({
                **s,
                #"count": s_count,
            })
        cat["subs"] = new_subs

    _nav_cache = nav
    _nav_cache_ts = now_ts

    nav = _apply_category_blacklist(nav)
    return nav


def category_context(top_slug: Optional[str], sub_slug: Optional[str], nav: Dict[str, Dict]):
    """Build template context for a category/subcategory page."""
    def _order_subs_selected_first(subs, sub_slug: str | None):
        """Return subs with the selected subcategory (by slug) first."""
        if not subs or not sub_slug:
            return subs
        head = [s for s in subs if sub_slug and sub_slug.lower() == s['slug']]
        tail = [s for s in subs if not (sub_slug and sub_slug.lower() == s['slug'])]
        return head + tail

    REVERSE_CATEGORY = {v: k for k, v in config()["categories"]["allow"].items()}
    label = REVERSE_CATEGORY.get(top_slug)
    cat = nav["cats"].get(label) or {}

    top_suma_href = cat.get("href") or urljoin(config()["base_url"], f"/{top_slug}")
    top_local_href = f"{top_slug}"

    # total products in this top-level category (all subs combined / top-level listing)
    top_count = cat.get("count", 0)

    subs = []
    for s in cat.get("subs", []):
        subs.append({
            "name": s["name"],
            "slug": s.get("slug"),
            "local_href": f"{top_slug}/{s.get('slug')}",
            "suma_href": s["href"],
            "count": s.get("count", 0),  # per-subcategory product count
        })

    current_local_href = (
        f"{top_slug}/{sub_slug}" if sub_slug
        else f"{top_slug}" if top_slug
        else ""
    )

    return {
        "category_label": label,
        "top_slug": top_slug,
        "sub_slug": sub_slug,
        "top_suma_href": top_suma_href,
        "top_local_href": top_local_href,

        # 👇 expose total count for the parent category
        "top_count": top_count,

        # list of subcategories, each with its own count
        "subs_local": _order_subs_selected_first(subs, sub_slug),

        #"current_local_href": current_local_href,
    }

def _apply_category_blacklist(nav: Dict[str, Dict]) -> Dict[str, Dict]:
    cats = nav.get("cats", {})
    out = {"cats": {}}
    for label, data in cats.items():
        top = (data or {}).get("slug")
        if not top or is_category_blocked(top):
            continue
        # filter subs
        subs = []
        for s in (data.get("subs") or []):
            sub_slug = s.get("slug")
            if sub_slug and not is_category_blocked(top, sub_slug):
                subs.append(s)
        # keep everything else (including counts)
        out["cats"][label] = {**data, "subs": subs}
    return out
