from __future__ import annotations

import sqlite3
from datetime import datetime, timedelta
from typing import Any, Dict, List


def _load_members(conn: sqlite3.Connection) -> List[Dict[str, Any]]:
    rows = conn.execute(
        """SELECT m.id, m.name, m.created_at, w.balance, w.total_consume,
                  c.last_visit_at, c.visit_count
           FROM store_members m
           LEFT JOIN store_wallet w ON w.member_id = m.id
           LEFT JOIN store_consumption_log c ON c.member_id = m.id
           WHERE m.status = 'active'
           ORDER BY m.id"""
    ).fetchall()
    out: List[Dict[str, Any]] = []
    today = datetime.now().date()
    cutoff30 = (today - timedelta(days=30)).strftime("%Y-%m-%d")
    cutoff60 = (today - timedelta(days=60)).strftime("%Y-%m-%d")
    cutoff90 = (today - timedelta(days=90)).strftime("%Y-%m-%d")

    for r in rows:
        mid = r["id"]
        spend_30 = conn.execute(
            """SELECT COALESCE(SUM(amount), 0) FROM store_transactions
               WHERE member_id=? AND type IN ('consume','cash')
               AND substr(created_at,1,10) >= ?""",
            (mid, cutoff30),
        ).fetchone()[0]
        visits_30 = conn.execute(
            """SELECT COUNT(*) FROM store_transactions
               WHERE member_id=? AND type IN ('consume','cash','card_use')
               AND substr(created_at,1,10) >= ?""",
            (mid, cutoff30),
        ).fetchone()[0]
        txn_90 = conn.execute(
            """SELECT COUNT(*) FROM store_transactions
               WHERE member_id=? AND type IN ('consume','cash','card_use')
               AND substr(created_at,1,10) >= ?""",
            (mid, cutoff90),
        ).fetchone()[0]
        last_visit = r["last_visit_at"]
        active_90d = int(txn_90) > 0
        if last_visit:
            try:
                active_90d = active_90d or (last_visit[:10] >= cutoff90)
            except (ValueError, TypeError, IndexError):
                active_90d = False
        dormant = True
        if last_visit:
            try:
                dormant = last_visit[:10] < cutoff60
            except (ValueError, TypeError, IndexError):
                dormant = int(r["visit_count"] or 0) == 0
        else:
            dormant = int(r["visit_count"] or 0) == 0

        is_new = False
        if r["created_at"]:
            try:
                cr = datetime.strptime(r["created_at"][:10], "%Y-%m-%d").date()
                is_new = (today - cr).days <= 90
            except ValueError:
                pass
        if int(r["visit_count"] or 0) <= 1:
            is_new = True

        out.append(
            {
                "id": mid,
                "name": r["name"],
                "balance": float(r["balance"] or 0),
                "total_consume": float(r["total_consume"] or 0),
                "spend_30d": float(spend_30),
                "visits_30d": int(visits_30),
                "last_visit_at": last_visit,
                "visit_count": int(r["visit_count"] or 0),
                "dormant": dormant,
                "is_new": is_new,
                "active_90d": active_90d,
            }
        )
    return out


def segment_preset_a(members: List[Dict[str, Any]]) -> Dict[str, List[Dict[str, Any]]]:
    buckets: Dict[str, List[Dict[str, Any]]] = {
        "高价值": [],
        "高频": [],
        "沉睡": [],
        "新客": [],
    }
    for m in members:
        brief = {
            "id": m["id"],
            "name": m["name"],
            "spend_30d": m["spend_30d"],
            "total_consume": m["total_consume"],
            "last_visit_at": m["last_visit_at"],
        }
        if m["spend_30d"] >= 2000 or m["total_consume"] >= 10000:
            buckets["高价值"].append(brief)
        elif m["visits_30d"] >= 4:
            buckets["高频"].append(brief)
        elif m["dormant"]:
            buckets["沉睡"].append(brief)
        elif m["is_new"]:
            buckets["新客"].append(brief)
    return buckets


def segment_preset_b(members: List[Dict[str, Any]]) -> Dict[str, List[Dict[str, Any]]]:
    buckets: Dict[str, List[Dict[str, Any]]] = {
        "高净值": [],
        "稳定复购": [],
        "沉睡": [],
        "新客": [],
    }
    for m in members:
        brief = {
            "id": m["id"],
            "name": m["name"],
            "balance": m["balance"],
            "last_visit_at": m["last_visit_at"],
        }
        bal = m["balance"]
        if bal > 5000:
            buckets["高净值"].append(brief)
        elif m["dormant"]:
            buckets["沉睡"].append(brief)
        elif m["is_new"]:
            buckets["新客"].append(brief)
        elif 1000 <= bal <= 5000 and m.get("active_90d"):
            buckets["稳定复购"].append(brief)
        elif m.get("active_90d"):
            buckets["稳定复购"].append(brief)
    return buckets


def run_segment(conn: sqlite3.Connection, preset: str) -> Dict[str, Any]:
    members = _load_members(conn)
    if preset.upper() == "A":
        seg = segment_preset_a(members)
        preset_name = "A"
    elif preset.upper() == "B":
        seg = segment_preset_b(members)
        preset_name = "B"
    else:
        raise ValueError(f"invalid preset: {preset}")

    return {
        "preset": preset_name,
        "total": len(members),
        "segments": {k: {"count": len(v), "members": v[:50]} for k, v in seg.items()},
        "raw_segments": seg,
    }


SEGMENT_NAMES_A = frozenset({"高价值", "高频", "沉睡", "新客"})
SEGMENT_NAMES_B = frozenset({"高净值", "稳定复购", "沉睡", "新客"})


def query_segment(
    conn: sqlite3.Connection,
    preset: str,
    name: str,
    *,
    limit: int = 200,
) -> Dict[str, Any]:
    result = run_segment(conn, preset)
    allowed = SEGMENT_NAMES_A if result["preset"] == "A" else SEGMENT_NAMES_B
    if name not in allowed:
        raise ValueError(f"invalid segment for preset {result['preset']}: {name}")
    raw = result["raw_segments"].get(name, [])
    return {
        "preset": result["preset"],
        "segment": name,
        "count": len(raw),
        "members": raw[:limit],
    }
