"""
BizNode Hosted Agent Service
==============================
Manages API-hosted agents for no-install tiers (Basic $20 through BizPlus $150).

These agents run on BizNode infrastructure — no local software installation needed.
BizNode provides LLM, knowledge base, and tool execution via its API.

Tiers:
    basic    ($20)  — 1 bot, AI agent identity, API-hosted tools
    standard ($50)  — 5 bots, same as basic x5
    pro      ($100) — escrow payments, earn DZIT, 1 published workflow
    bizplus  ($150) — up to 5 workflows
    bizmax   ($200) — local node software + BizPlus benefits
    biznode  ($499) — USB hardware key + full platform
    onezbnode($1500)— BizNode + 1500 DZIT credits
"""

import json
import logging
import os
import random
import string
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, List, Optional

_PROJECT_ROOT = str(Path(__file__).resolve().parent.parent)
if _PROJECT_ROOT not in sys.path:
    sys.path.insert(0, _PROJECT_ROOT)

from memory.database import get_connection

log = logging.getLogger(__name__)

# Tier definitions
TIER_CONFIG = {
    "basic":     {"price_usd": 20,   "max_bots": 1, "escrow": False, "earn_dzit": False, "max_workflows": 0, "local_node": False, "usb_key": False, "bonus_dzit": 10},
    "standard":  {"price_usd": 50,   "max_bots": 5, "escrow": False, "earn_dzit": False, "max_workflows": 0, "local_node": False, "usb_key": False, "bonus_dzit": 10},
    "pro":       {"price_usd": 100,  "max_bots": 5, "escrow": True,  "earn_dzit": True,  "max_workflows": 1, "local_node": False, "usb_key": False, "bonus_dzit": 10},
    "bizplus":   {"price_usd": 150,  "max_bots": 5, "escrow": True,  "earn_dzit": True,  "max_workflows": 5, "local_node": False, "usb_key": False, "bonus_dzit": 10},
    "bizmax":    {"price_usd": 200,  "max_bots": 1, "escrow": True,  "earn_dzit": True,  "max_workflows": 5, "local_node": True,  "usb_key": False, "bonus_dzit": 10},
    "biznode":   {"price_usd": 499,  "max_bots": 5, "escrow": True,  "earn_dzit": True,  "max_workflows": 5, "local_node": True,  "usb_key": True,  "bonus_dzit": 10},
    "onezbnode": {"price_usd": 1500, "max_bots": 5, "escrow": True,  "earn_dzit": True,  "max_workflows": 5, "local_node": True,  "usb_key": True,  "bonus_dzit": 1510},
}


def _generate_hosted_agent_id() -> str:
    """Generate a unique hosted agent ID like BZHA-A1B2C."""
    chars = string.ascii_uppercase + string.digits
    suffix = "".join(random.choices(chars, k=5))
    return f"BZHA-{suffix}"


class HostedAgentService:
    """Manages API-hosted agents for no-install BizNode tiers."""

    def __init__(self):
        self._db_mod = None

    def _db(self):
        """Lazy-load database module."""
        if self._db_mod is None:
            import importlib.util
            spec = importlib.util.spec_from_file_location(
                "_db", os.path.join(_PROJECT_ROOT, "memory", "database.py")
            )
            mod = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(mod)
            self._db_mod = mod
        return self._db_mod

    # ------------------------------------------------------------------
    # Registration
    # ------------------------------------------------------------------

    def register_agent(
        self,
        owner_email: str,
        owner_name: str = "",
        telegram_id: str = "",
        tier: str = "basic",
        bot_token: str = "",
        bot_username: str = "",
        business_name: str = "",
        business_description: str = "",
        industry: str = "general",
    ) -> Dict[str, Any]:
        """Register a new hosted agent. Returns agent_id and initial DZIT balance."""
        if tier not in TIER_CONFIG:
            return {"success": False, "error": f"Invalid tier: {tier}. Valid: {list(TIER_CONFIG.keys())}"}

        config = TIER_CONFIG[tier]

        # Enforce max_bots per email — count existing agents for this email
        db = self._db()
        existing = db.list_hosted_agents()
        email_agents = [a for a in existing if a.get("owner_email") == owner_email and a.get("status") == "active"]
        if len(email_agents) >= config["max_bots"]:
            return {
                "success": False,
                "error": f"Bot limit reached. {tier.upper()} tier allows {config['max_bots']} bot(s). "
                         f"You have {len(email_agents)} active bot(s) on {owner_email}. "
                         f"Upgrade your tier for more bots.",
                "current_bots": len(email_agents),
                "max_bots": config["max_bots"],
            }

        agent_id = _generate_hosted_agent_id()

        try:
            db.create_hosted_agent(
                agent_id=agent_id,
                owner_email=owner_email,
                owner_name=owner_name,
                telegram_id=telegram_id,
                tier=tier,
                bot_token=bot_token,
                bot_username=bot_username,
                business_name=business_name,
                business_description=business_description,
                industry=industry,
                max_bots=config["max_bots"],
            )
        except Exception as exc:
            log.error("Failed to register hosted agent: %s", exc)
            return {"success": False, "error": str(exc)}

        # Credit initial DZIT bonus
        bonus = config["bonus_dzit"]
        if bonus > 0:
            db.adjust_agent_balance(agent_id, dzit_delta=bonus)

        log.info("Hosted agent registered: %s (tier=%s, email=%s)", agent_id, tier, owner_email)
        return {
            "success": True,
            "agent_id": agent_id,
            "tier": tier,
            "max_bots": config["max_bots"],
            "dzit_balance": bonus,
            "features": {
                "escrow": config["escrow"],
                "earn_dzit": config["earn_dzit"],
                "max_workflows": config["max_workflows"],
                "local_node": config["local_node"],
                "usb_key": config["usb_key"],
            },
        }

    # ------------------------------------------------------------------
    # Queries
    # ------------------------------------------------------------------

    def get_agent(self, agent_id: str) -> Optional[Dict]:
        """Get hosted agent details."""
        db = self._db()
        agent = db.get_hosted_agent(agent_id)
        if agent:
            tier = agent.get("tier", "basic")
            config = TIER_CONFIG.get(tier, TIER_CONFIG["basic"])
            agent["tier_config"] = config
        return agent

    def get_agent_by_email(self, email: str) -> Optional[Dict]:
        """Find hosted agent by owner email."""
        db = self._db()
        return db.get_hosted_agent_by_email(email)

    def list_agents(self, tier: str = None, status: str = None) -> List[Dict]:
        """List all hosted agents."""
        db = self._db()
        return db.list_hosted_agents(tier=tier, status=status)

    # ------------------------------------------------------------------
    # Tier management
    # ------------------------------------------------------------------

    def upgrade_tier(self, agent_id: str, new_tier: str) -> Dict[str, Any]:
        """Upgrade an agent's tier."""
        if new_tier not in TIER_CONFIG:
            return {"success": False, "error": f"Invalid tier: {new_tier}"}

        db = self._db()
        agent = db.get_hosted_agent(agent_id)
        if not agent:
            return {"success": False, "error": "Agent not found"}

        config = TIER_CONFIG[new_tier]
        ok = db.update_hosted_agent(
            agent_id,
            tier=new_tier,
            max_bots=config["max_bots"],
        )
        if ok:
            log.info("Agent %s upgraded to %s", agent_id, new_tier)
            return {"success": True, "agent_id": agent_id, "new_tier": new_tier}
        return {"success": False, "error": "Update failed"}

    # ------------------------------------------------------------------
    # Balance operations
    # ------------------------------------------------------------------

    def get_balance(self, agent_id: str) -> Dict[str, Any]:
        """Get agent's current balance."""
        db = self._db()
        agent = db.get_hosted_agent(agent_id)
        if not agent:
            return {"success": False, "error": "Agent not found"}
        return {
            "success": True,
            "agent_id": agent_id,
            "dzit_balance": agent.get("dzit_balance", 0),
            "bzeusd_balance": agent.get("bzeusd_balance", 0),
        }

    def credit_dzit(self, agent_id: str, amount: float, reason: str = "") -> Dict[str, Any]:
        """Credit DZIT to an agent."""
        db = self._db()
        ok = db.adjust_agent_balance(agent_id, dzit_delta=amount)
        if ok:
            log.info("Credited %s DZIT to %s: %s", amount, agent_id, reason)
            return {"success": True, "credited": amount, "currency": "DZIT"}
        return {"success": False, "error": "Agent not found"}

    def deduct_dzit(self, agent_id: str, amount: float, reason: str = "") -> Dict[str, Any]:
        """Deduct DZIT from an agent (checks balance)."""
        db = self._db()
        agent = db.get_hosted_agent(agent_id)
        if not agent:
            return {"success": False, "error": "Agent not found"}
        if agent.get("dzit_balance", 0) < amount:
            return {"success": False, "error": "Insufficient DZIT balance"}
        ok = db.adjust_agent_balance(agent_id, dzit_delta=-amount)
        if ok:
            return {"success": True, "deducted": amount, "currency": "DZIT"}
        return {"success": False, "error": "Deduction failed"}

    # ------------------------------------------------------------------
    # Hosted tool execution
    # ------------------------------------------------------------------

    def execute_hosted_tool(
        self, agent_id: str, tool_name: str, params: Dict
    ) -> Dict[str, Any]:
        """
        Execute a tool on behalf of a hosted agent using BizNode infrastructure.
        Available for all tiers — this is what makes no-install tiers work.
        """
        db = self._db()
        agent = db.get_hosted_agent(agent_id)
        if not agent:
            return {"success": False, "error": "Agent not found"}
        if agent.get("status") != "active":
            return {"success": False, "error": "Agent is not active"}

        # Route to local tool registry
        try:
            from automation.registry import get_registry
            registry = get_registry()
            if registry.has(tool_name):
                tool = registry.get(tool_name)
                result = tool.run(**params)
                return {"success": True, "data": result}
            return {"success": False, "error": f"Tool '{tool_name}' not available"}
        except Exception as exc:
            log.error("Hosted tool execution failed: %s", exc)
            return {"success": False, "error": str(exc)}

    # ------------------------------------------------------------------
    # Tier info (static)
    # ------------------------------------------------------------------

    @staticmethod
    def get_tier_info(tier: str = None) -> Dict[str, Any]:
        """Get tier configuration details."""
        if tier:
            config = TIER_CONFIG.get(tier)
            if not config:
                return {"success": False, "error": f"Unknown tier: {tier}"}
            return {"success": True, "tier": tier, **config}
        return {"success": True, "tiers": TIER_CONFIG}

    @staticmethod
    def get_all_tiers() -> List[Dict]:
        """Get all tiers formatted for display."""
        tiers = []
        for name, config in TIER_CONFIG.items():
            tiers.append({
                "tier": name,
                "price_usd": config["price_usd"],
                "max_bots": config["max_bots"],
                "escrow": config["escrow"],
                "earn_dzit": config["earn_dzit"],
                "max_workflows": config["max_workflows"],
                "local_node": config["local_node"],
                "usb_key": config["usb_key"],
                "bonus_dzit": config["bonus_dzit"],
            })
        return tiers
