"""
In-memory + DB-backed session state for WhatsApp conversations.
Tracks cart, checkout state, and pending confirmations per phone number.
"""
import json
import logging
import re
from typing import Optional

from django.core.cache import cache

logger = logging.getLogger(__name__)

SESSION_TTL = 60 * 60 * 24 * 30  # 30 days


def normalize_phone(phone: str) -> str:
    """
    Normalize WhatsApp phone identifiers to stable cache keys.
    """
    raw = str(phone or "").strip()
    if not raw:
        return ""
    digits = re.sub(r"\D", "", raw)
    return digits or raw


def _key(phone: str, suffix: str) -> str:
    return f"wa_session:{normalize_phone(phone)}:{suffix}"


def get_cart(phone: str) -> list:
    cart = cache.get(_key(phone, "cart"), [])
    # Keep active carts alive while user is still chatting.
    if cart:
        cache.set(_key(phone, "cart"), cart, SESSION_TTL)
    return cart


def set_cart(phone: str, items: list):
    cache.set(_key(phone, "cart"), items, SESSION_TTL)


def add_to_cart(phone: str, product: dict, qty: int = 1) -> list:
    cart = get_cart(phone)
    for item in cart:
        if item["product_id"] == product["product_id"]:
            item["quantity"] += qty
            set_cart(phone, cart)
            return cart
    cart.append({
        "product_id": product["product_id"],
        "name": product["name"],
        "price": product["price"],
        "currency": product.get("currency", "GHS"),
        "store_name": product.get("store_name", ""),
        "vendor_id": product.get("vendor_id"),
        "quantity": qty,
        "image_url": product.get("image_url", ""),
    })
    set_cart(phone, cart)
    return cart


def remove_from_cart(phone: str, product_id) -> list:
    cart = [i for i in get_cart(phone) if str(i["product_id"]) != str(product_id)]
    set_cart(phone, cart)
    return cart


def clear_cart(phone: str):
    cache.delete(_key(phone, "cart"))


def cart_total(phone: str) -> float:
    return sum(i["price"] * i["quantity"] for i in get_cart(phone))


# ── Pending confirmations ─────────────────────────────────────────────────

def set_pending(phone: str, action: str, data: dict):
    """Store something awaiting a yes/no from the user."""
    cache.set(_key(phone, "pending"), {"action": action, "data": data}, SESSION_TTL)


def get_pending(phone: str) -> Optional[dict]:
    return cache.get(_key(phone, "pending"))


def clear_pending(phone: str):
    cache.delete(_key(phone, "pending"))


# ── Checkout state ────────────────────────────────────────────────────────

def set_checkout_state(phone: str, state: str, data: Optional[dict] = None):
    cache.set(_key(phone, "checkout"), {"state": state, "data": data or {}}, SESSION_TTL)


def get_checkout_state(phone: str) -> Optional[dict]:
    return cache.get(_key(phone, "checkout"))


def clear_checkout_state(phone: str):
    cache.delete(_key(phone, "checkout"))


# ── Last shown products ───────────────────────────────────────────────────

def set_last_products(phone: str, products: list):
    """Keep the last batch of products so user can reference them by number."""
    slim = []
    for p in products[:10]:
        slim.append({
            "product_id": p.get("id") or p.get("external_id"),
            "name": p.get("name", ""),
            "price": float(p.get("price") or 0),
            "currency": p.get("currency", "GHS"),
            "store_name": p.get("store_name", ""),
            "vendor_id": p.get("vendor_id"),
            "source": p.get("source", "external"),
            "image_url": p.get("image_url", ""),
            "product_url": p.get("product_url", ""),
            "brand": p.get("brand", ""),
            "description": p.get("description", ""),
            "in_stock": p.get("in_stock", True),
            "quantity": p.get("quantity", 0),
        })
    cache.set(_key(phone, "last_products"), slim, SESSION_TTL)


def get_last_products(phone: str) -> list:
    return cache.get(_key(phone, "last_products"), [])


def get_product_by_number(phone: str, number: int) -> Optional[dict]:
    products = get_last_products(phone)
    idx = number - 1
    if 0 <= idx < len(products):
        return products[idx]
    return None