"""
BizNode Tier Manager
=====================
Central source of truth for license tiers and feature gating.

Tiers:
    TRIAL  — 10 days, 1 bot, core features only
    BASIC  — License key (BZN-XXXXX-XXXXX-XXXXX), 1 bot, core features, server-validated
    PRO    — USB license, up to 5 bots, all features + plugins

Usage:
    from services.tier_manager import get_current_tier, is_feature_allowed, TierLevel

    if is_feature_allowed("bizchannel"):
        # load bizchannel plugin

    max_bots = get_max_bots()
"""

from __future__ import annotations

import enum
import os
import json
import logging
from pathlib import Path
from typing import Optional
from functools import wraps

logger = logging.getLogger("biznode.tier")

_ROOT = Path(__file__).resolve().parent.parent


# ---------------------------------------------------------------------------
# Tier definitions
# ---------------------------------------------------------------------------

class TierLevel(enum.IntEnum):
    """License tiers in ascending order of capabilities."""
    TRIAL = 0
    BASIC = 1
    PRO   = 2


# Maximum bots per tier
MAX_BOTS = {
    TierLevel.TRIAL: 1,
    TierLevel.BASIC: 1,
    TierLevel.PRO:   5,
}

# ---------------------------------------------------------------------------
# Commercial tier definitions (7-tier marketplace system)
# ---------------------------------------------------------------------------

COMMERCIAL_TIERS = {
    "basic":     {"price_usd": 20,   "max_bots": 1, "tier_level": TierLevel.BASIC, "escrow": False, "earn_dzit": False, "max_workflows": 0, "local_node": False, "usb_key": False, "bonus_dzit": 10},
    "standard":  {"price_usd": 50,   "max_bots": 5, "tier_level": TierLevel.BASIC, "escrow": False, "earn_dzit": False, "max_workflows": 0, "local_node": False, "usb_key": False, "bonus_dzit": 10},
    "pro":       {"price_usd": 100,  "max_bots": 5, "tier_level": TierLevel.PRO,   "escrow": True,  "earn_dzit": True,  "max_workflows": 1, "local_node": False, "usb_key": False, "bonus_dzit": 10},
    "bizplus":   {"price_usd": 150,  "max_bots": 5, "tier_level": TierLevel.PRO,   "escrow": True,  "earn_dzit": True,  "max_workflows": 5, "local_node": False, "usb_key": False, "bonus_dzit": 10},
    "bizmax":    {"price_usd": 200,  "max_bots": 1, "tier_level": TierLevel.BASIC, "escrow": True,  "earn_dzit": True,  "max_workflows": 5, "local_node": True,  "usb_key": False, "bonus_dzit": 10},
    "biznode":   {"price_usd": 499,  "max_bots": 5, "tier_level": TierLevel.PRO,   "escrow": True,  "earn_dzit": True,  "max_workflows": 5, "local_node": True,  "usb_key": True,  "bonus_dzit": 10},
    "onezbnode": {"price_usd": 1500, "max_bots": 5, "tier_level": TierLevel.PRO,   "escrow": True,  "earn_dzit": True,  "max_workflows": 5, "local_node": True,  "usb_key": True,  "bonus_dzit": 1510},
}

# ---------------------------------------------------------------------------
# Feature registry — maps feature name to minimum required tier
# ---------------------------------------------------------------------------

FEATURE_REGISTRY: dict[str, TierLevel] = {
    # ── Core features (all tiers) ──
    "telegram_bot":       TierLevel.TRIAL,
    "dashboard":          TierLevel.TRIAL,
    "rag_kb":             TierLevel.TRIAL,
    "llm_chat":           TierLevel.TRIAL,
    "email_service":      TierLevel.TRIAL,
    "otp_service":        TierLevel.TRIAL,
    "workflow_engine":    TierLevel.TRIAL,
    "local_backup":       TierLevel.TRIAL,

    # ── Pro-only features ──
    "bizchannel":             TierLevel.PRO,
    "admin_tools":            TierLevel.PRO,
    "affiliate_service":      TierLevel.PRO,
    "bizbrain_service":       TierLevel.PRO,
    "crypto_service":         TierLevel.PRO,
    "customer_engagement":    TierLevel.PRO,
    "group_ad_service":       TierLevel.PRO,
    "stripe_service":         TierLevel.PRO,
    "promo_email_service":    TierLevel.PRO,
    "transaction_service":    TierLevel.PRO,
    "multi_bot":              TierLevel.PRO,
    "cloud_backup":           TierLevel.PRO,
    "agent_monitoring":       TierLevel.PRO,
    "nodes_monitoring":       TierLevel.PRO,
    "agent_employment":       TierLevel.PRO,
    "api_service":            TierLevel.PRO,

    # ── Marketplace features ──
    "tool_publishing":        TierLevel.BASIC,    # publish tools to registry
    "tool_calling":           TierLevel.BASIC,    # call other bots' tools
    "escrow_payments":        TierLevel.PRO,      # escrow for paid tool calls
    "workflow_publishing":    TierLevel.PRO,      # publish workflows to site
    "hosted_agent":           TierLevel.BASIC,    # API-hosted agent (no-install)

    # ── Blog features ──
    "blog_posting":           TierLevel.BASIC,   # publish to blog.1bz.biz (Basic=1/mo, Pro=5/mo)

    # ── DataVault features ──
    "datavault_access":       TierLevel.BASIC,   # browse, search, purchase reports
    "datavault_generate":     TierLevel.PRO,     # run plugins to create reports
}


# ---------------------------------------------------------------------------
# Cached tier — determined once at startup
# ---------------------------------------------------------------------------

_cached_tier: Optional[TierLevel] = None
_cached_tier_info: Optional[dict] = None


def _determine_tier() -> tuple[TierLevel, dict]:
    """
    Determine the current license tier by checking (in order):
      1. USB Pro license
      2. Basic license key (.license_key file)
      3. Trial / registration
    Returns (tier, extra_info_dict).
    """
    extra = {}

    # 1. Check USB Pro license
    try:
        from services.license_validator import validate_license
        result = validate_license()
        if result.valid:
            extra["order_id"] = result.order_id
            extra["expiry"] = result.expiry
            extra["days_remaining"] = result.days_remaining
            extra["usb_path"] = result.usb_path
            return TierLevel.PRO, extra
    except Exception as e:
        logger.warning(f"USB license check error: {e}")

    # 2. Check Basic license key
    try:
        from services.license_validator import validate_basic_license
        from launcher import _machine_fingerprint
        fingerprint = _machine_fingerprint()
        result = validate_basic_license(fingerprint=fingerprint)
        if result.valid:
            extra["license_key"] = result.registration_key
            extra["expiry"] = result.expiry
            extra["days_remaining"] = result.days_remaining
            return TierLevel.BASIC, extra
    except Exception as e:
        logger.debug(f"Basic license check: {e}")

    # 3. Fallback to Trial
    reg_file = _ROOT / ".registration"
    if reg_file.exists():
        try:
            reg = json.loads(reg_file.read_text(encoding="utf-8"))
            extra["registration_id"] = reg.get("registration_id")
            extra["trial_expires_at"] = reg.get("trial_expires_at")
            extra["days_remaining"] = reg.get("days_remaining")
        except Exception:
            pass

    return TierLevel.TRIAL, extra


def get_current_tier() -> TierLevel:
    """Get the current license tier (cached after first call)."""
    global _cached_tier
    if _cached_tier is None:
        _cached_tier, _ = _determine_tier()
        logger.info(f"License tier: {_cached_tier.name}")
    return _cached_tier


def refresh_tier() -> TierLevel:
    """Force re-evaluation of the license tier."""
    global _cached_tier, _cached_tier_info
    _cached_tier = None
    _cached_tier_info = None
    return get_current_tier()


# ---------------------------------------------------------------------------
# Feature gating
# ---------------------------------------------------------------------------

def is_feature_allowed(feature_name: str) -> bool:
    """Check if a feature is allowed for the current tier."""
    required = FEATURE_REGISTRY.get(feature_name)
    if required is None:
        # Unknown feature — allow by default (don't break new code)
        logger.warning(f"Unknown feature '{feature_name}' — allowing by default")
        return True
    return get_current_tier() >= required


def get_max_bots() -> int:
    """Get the maximum number of bots allowed for the current tier."""
    return MAX_BOTS.get(get_current_tier(), 1)


def require_tier(minimum: TierLevel):
    """
    Decorator for FastAPI endpoints — returns 403 if tier is insufficient.

    Usage:
        @app.get("/api/pro-feature")
        @require_tier(TierLevel.PRO)
        async def pro_feature():
            ...
    """
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            current = get_current_tier()
            if current < minimum:
                from fastapi import HTTPException
                raise HTTPException(
                    status_code=403,
                    detail={
                        "error": f"This feature requires {minimum.name} tier.",
                        "current_tier": current.name,
                        "upgrade_url": "https://biznode.1bz.biz",
                        "message": f"Upgrade to {minimum.name} at https://biznode.1bz.biz to unlock this feature.",
                    }
                )
            return await func(*args, **kwargs)
        return wrapper
    return decorator


# ---------------------------------------------------------------------------
# Tier info (for dashboard / status display)
# ---------------------------------------------------------------------------

def tier_info() -> dict:
    """
    Return full tier information for display.
    Includes which features are enabled/disabled for the current tier.
    """
    global _cached_tier_info
    if _cached_tier_info is not None:
        return _cached_tier_info

    tier = get_current_tier()
    _, extra = _determine_tier()

    enabled = []
    disabled = []
    for feature, min_tier in sorted(FEATURE_REGISTRY.items()):
        if tier >= min_tier:
            enabled.append(feature)
        else:
            disabled.append(feature)

    _cached_tier_info = {
        "tier": tier.name.lower(),
        "tier_level": tier.value,
        "max_bots": MAX_BOTS.get(tier, 1),
        "features_enabled": enabled,
        "features_disabled": disabled,
        "features_total": len(FEATURE_REGISTRY),
        **extra,
    }
    return _cached_tier_info


def get_commercial_tier(tier_name: str) -> Optional[dict]:
    """Get commercial tier details by name."""
    return COMMERCIAL_TIERS.get(tier_name)


def get_commercial_tiers() -> dict:
    """Get all commercial tier definitions."""
    return COMMERCIAL_TIERS


# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    import sys
    sys.path.insert(0, str(_ROOT))

    info = tier_info()
    print()
    print("=" * 54)
    print("  BizNode Tier Status")
    print("=" * 54)
    print(f"  Tier       : {info['tier'].upper()}")
    print(f"  Max bots   : {info['max_bots']}")
    print(f"  Features   : {len(info['features_enabled'])}/{info['features_total']}")
    print()

    if info["features_enabled"]:
        print("  Enabled:")
        for f in info["features_enabled"]:
            print(f"    + {f}")
    if info["features_disabled"]:
        print()
        print("  Pro-only (upgrade to unlock):")
        for f in info["features_disabled"]:
            print(f"    - {f}")
    print()
    print("=" * 54)
